blob: c39aa25b93ce9cbd52c992052ee0f8b43984dd30 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package flex2.tools.oem.internal;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import flex2.compiler.Source;
import flex2.compiler.SourceList;
import flex2.compiler.common.Configuration;
import flex2.compiler.common.Configuration.RslPathInfo;
import flex2.compiler.io.FileUtil;
import flex2.compiler.io.VirtualFile;
import flex2.linker.SimpleMovie;
import flex2.tools.VersionInfo;
import flex2.tools.oem.Message;
import flex2.tools.oem.Report;
/**
* A Report implementation.
*
* @version 2.0.1
* @author Clement Wong
*/
public class OEMReport implements Report
{
public OEMReport(List<Source> sources, SimpleMovie movie, Configuration configuration,
SourceList sourceList, String configurationReport, List<Message> messages)
{
this(sources, movie, configuration, sourceList, configurationReport, messages, null);
}
public OEMReport(List<Source> sources, SimpleMovie movie, Configuration configuration,
SourceList sourceList, String configurationReport, List<Message> messages,
Map<String, VirtualFile> archiveFiles)
{
if (sourceList != null)
{
sourceListPaths = sourceList.getPaths();
}
init(sources, /* null,*/
configuration == null ? null : configuration.getResourceBundles(),
archiveFiles, configuration);
//processFrames(movie);
processMessages(messages);
this.frameCount = 1 ;
this.configurationReport = configurationReport;
defaultWidth = configuration != null ? configuration.defaultWidth() : 0;
defaultHeight = configuration != null ? configuration.defaultHeight() : 0;
width = 0;
height = 0;
widthPercent = 0.0;
heightPercent = 0.0;
if (movie != null)
{
linkReport = movie.getLinkReport();
sizeReport = movie.getSizeReport();
bgColor = movie.bgcolor.color;
pageTitle = movie.pageTitle;
if (movie.userSpecifiedWidth)
{
width = movie.width;
}
else if (configuration != null)
{
String percent = configuration.widthPercent();
if (percent != null)
{
percent = percent.trim();
// Percent character is expected but allow it to be optional.
if (percent.length() >= 1 &&
percent.charAt(percent.length() - 1) == '%')
{
percent = percent.substring(0, percent.length() - 1);
}
try
{
widthPercent = Double.parseDouble(percent) / 100;
}
catch(NumberFormatException ex) {}
}
}
if (movie.userSpecifiedHeight)
{
height = movie.height;
}
else if (configuration != null)
{
String percent = configuration.heightPercent();
if (percent != null)
{
percent = percent.trim();
// Percent character is expected but allow it to be optional.
if (percent.length() >= 1 &&
percent.charAt(percent.length() - 1) == '%')
{
percent = percent.substring(0, percent.length() - 1);
}
try
{
heightPercent = Double.parseDouble(percent) / 100;
}
catch(NumberFormatException ex) {}
}
}
}
else
{
linkReport = null;
sizeReport = null;
bgColor = 0;
pageTitle = null;
}
}
private void init(List<Source> sources, /* List<CompilationUnit> exportedUnits,*/ Set<String> resourceBundles,
Map<String, VirtualFile> archiveFiles,
Configuration configuration)
{
TreeSet<String> sourceNames = new TreeSet<String>();
TreeSet<String> assetNames = new TreeSet<String>();
TreeSet<String> libraryNames = new TreeSet<String>();
data = new HashMap<String, Data>();
locations = new HashMap<String, String>();
if (sources != null)
{
//processSources(sources, sourceNames, assetNames, libraryNames, data, locations);
}
timestamps = new HashMap<String, Long>();
// Store timestamps for each path in the SourceList, so
// contentUpdated() can report true if new sources are added
// to the SourceList.
if (sourceListPaths != null)
{
for (File path : sourceListPaths)
{
storeTimestamps(path);
}
}
compiler_SourceNames = toArray(sourceNames);
storeTimestamps(compiler_SourceNames);
compiler_AssetNames = toArray(assetNames);
storeTimestamps(compiler_AssetNames);
compiler_LibraryNames = toArray(libraryNames);
storeTimestamps(compiler_LibraryNames);
resourceBundleNames = toArray(resourceBundles);
sourceNames.clear();
assetNames.clear();
libraryNames.clear();
//processCompilationUnits(exportedUnits, sourceNames, assetNames, libraryNames);
// Add files to the assets set so they are included in the timestamps.
// FB calls the OEMReports.contentUpdated() method to determine if a
// file has changed and if so it will recompile. This code was added
// for the specific case where a default.css file was modified but FB
// didn't think it needed to recompile because default.css wasn't in
// the timestamps map.
if (archiveFiles != null)
{
for (String fileName: archiveFiles.keySet())
{
assetNames.add(fileName);
}
}
linker_SourceNames = toArray(sourceNames);
storeTimestamps(linker_SourceNames);
linker_AssetNames = toArray(assetNames);
storeTimestamps(linker_AssetNames);
linker_LibraryNames = toArray(libraryNames);
storeTimestamps(linker_LibraryNames);
// Add libraries linked as RSLs to the timestamp map.
// Saving the digests of the libraries would be better than a
// timestamp since we would know if the digest changed, not
// just something in the library. We can't compare digests because
// contentUpdated() does not have access to the swcs we will
// compile with. Timestamps may cause us to recompile an app when
// the RSL has not been modified but that should be pretty rare.
if (configuration != null)
{
List<RslPathInfo> rslPathInfoList = configuration.getRslPathInfo();
if (rslPathInfoList.size() > 0)
{
String[] rslPaths = new String[rslPathInfoList.size()];
int i = 0;
for (RslPathInfo rslPathInfo : rslPathInfoList)
{
rslPaths[i++] = rslPathInfo.getSwcVirtualFile().getName();
}
storeTimestamps(rslPaths);
}
}
}
private void storeTimestamps(File path)
{
// (SDK-30367) Timestamp caching was added after Flex 3 but it causes
// performance issues as it also checks files under hidden directories,
// e.g. .svn. Skipping checking the timestamp of hidden files and
// folders helps reduce the time spent in this method.
if (path.isHidden())
return;
timestamps.put(FileUtil.getCanonicalPath(path), path.lastModified());
for (File file : path.listFiles())
{
if (file.isDirectory())
{
storeTimestamps(file);
}
}
}
private void storeTimestamps(String[] a)
{
if (a != null)
{
for (String fileName : a)
{
if ((fileName != null) && !timestamps.containsKey(fileName))
{
timestamps.put(fileName, new File(fileName).lastModified());
}
}
}
}
private String[] compiler_SourceNames, compiler_AssetNames, compiler_LibraryNames;
private String[] linker_SourceNames, linker_AssetNames, linker_LibraryNames;
private String[] resourceBundleNames;
private Map<String, Data> data;
private Map<String, String> locations;
private Map<String, Long> timestamps;
private int frameCount;
private int bgColor, defaultWidth, defaultHeight, width, height;
private String pageTitle;
private double widthPercent, heightPercent;
private String linkReport, sizeReport, configurationReport;
private Message[] messages;
//private String[][] assetNames, definitionNames;
private List<File> sourceListPaths;
public boolean contentUpdated()
{
// AJH for now, just return true to force another build. Someday be smarter about what sources
// we have and what their time stamps are.
return true;
/*
for (Iterator<String> i = timestamps.keySet().iterator(); i.hasNext(); )
{
String path = i.next();
Long ts = timestamps.get(path);
File f = new File(path);
if (!f.exists() || f.lastModified() != ts.longValue())
{
return true;
}
}
return false;
*/
}
public String[] getSourceNames(Object report)
{
return (COMPILER.equals(report)) ? compiler_SourceNames : (LINKER.equals(report)) ? linker_SourceNames : null;
}
public String[] getAssetNames(int frame)
{
return new String[0];
//return assetNames[frame - 1];
}
public String[] getAssetNames(Object report)
{
return (COMPILER.equals(report)) ? compiler_AssetNames : (LINKER.equals(report)) ? linker_AssetNames : null;
}
public String[] getLibraryNames(Object report)
{
return (COMPILER.equals(report)) ? compiler_LibraryNames : (LINKER.equals(report)) ? linker_LibraryNames : null;
}
public String[] getResourceBundleNames()
{
return resourceBundleNames;
}
public String[] getDefinitionNames(int frame)
{
return new String[0];
//return definitionNames[frame - 1];
}
public String[] getDefinitionNames(String sourceName)
{
Data d = data.get(sourceName);
return d == null ? null : d.definitions;
}
public String getLocation(String definition)
{
return locations.get(definition);
}
public String[] getDependencies(String definition)
{
String location = getLocation(definition);
if (location != null)
{
Data d = data.get(location);
return d == null ? null : d.dependencies;
}
else
{
return null;
}
}
public String[] getPrerequisites(String definition)
{
String location = getLocation(definition);
if (location != null)
{
Data d = data.get(location);
return d == null ? null : d.prerequisites;
}
else
{
return null;
}
}
public long writeLinkReport(Writer out) throws IOException
{
long size = 0;
if (linkReport != null)
{
out.write(linkReport);
out.flush();
size = linkReport.length();
}
return size;
}
public long writeSizeReport(Writer out) throws IOException
{
long size = 0;
if (sizeReport != null)
{
out.write(sizeReport);
out.flush();
size = sizeReport.length();
}
return size;
}
public long writeConfigurationReport(Writer out) throws IOException
{
long size = 0;
if (configurationReport != null)
{
out.write(configurationReport);
out.flush();
size = configurationReport.length();
}
return size;
}
public int getBackgroundColor()
{
return bgColor;
}
public String getPageTitle()
{
return pageTitle;
}
public int getDefaultWidth()
{
return defaultWidth;
}
public int getDefaultHeight()
{
return defaultHeight;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public double getWidthPercent()
{
return widthPercent;
}
public double getHeightPercent()
{
return heightPercent;
}
public String getCompilerVersion()
{
return VersionInfo.buildMessage();
}
public Message[] getMessages()
{
return messages;
}
public int getFrameCount()
{
return frameCount;
}
/*
private void processCompilationUnits(List<CompilationUnit> units, TreeSet<String> sourceNames,
TreeSet<String> assetNames, TreeSet<String> libraryNames)
{
for (int i = 0, length = units == null ? 0 : units.size(); i < length; i++)
{
CompilationUnit u = units.get(i);
Source s = (u == null) ? null : u.getSource();
if (s == null)
{
continue;
}
if (s.isFileSpecOwner() || s.isSourceListOwner() || s.isSourcePathOwner() || s.isResourceBundlePathOwner())
{
sourceNames.add(s.getName());
for (Iterator j = s.getFileIncludes(); j.hasNext(); )
{
VirtualFile f = (VirtualFile) j.next();
sourceNames.add(f.getName());
}
if (u.hasAssets())
{
for (Iterator j = u.getAssets().iterator(); j.hasNext(); )
{
Map.Entry e = (Map.Entry) j.next();
AssetInfo assetInfo = (AssetInfo) e.getValue();
VirtualFile path = assetInfo.getPath();
if (path != null)
{
assetNames.add(path.getName());
}
}
}
}
else if (s.isSwcScriptOwner())
{
String location = ((SwcScript) s.getOwner()).getLibrary().getSwcLocation();
libraryNames.add(location);
}
}
}
private void processSources(List<Source> sources, TreeSet<String> sourceNames, TreeSet<String> assetNames,
TreeSet<String> libraryNames, Map<String, Data> data, Map<String, String> locations)
{
for (Source s : sources)
{
CompilationUnit u = (s == null) ? null : s.getCompilationUnit();
if (s == null)
{
continue;
}
if (s.isFileSpecOwner() || s.isSourceListOwner() || s.isSourcePathOwner() || s.isResourceBundlePathOwner())
{
sourceNames.add(s.getName());
for (Iterator j = s.getFileIncludes(); j.hasNext(); )
{
VirtualFile f = (VirtualFile) j.next();
sourceNames.add(f.getName());
}
if (u.hasAssets())
{
for (Iterator j = u.getAssets().iterator(); j.hasNext(); )
{
Map.Entry e = (Map.Entry) j.next();
AssetInfo assetInfo = (AssetInfo) e.getValue();
VirtualFile path = assetInfo.getPath();
if (path != null)
{
assetNames.add(assetInfo.getPath().getName());
}
}
}
if (locations != null)
{
for (int j = 0, size = u.topLevelDefinitions.size(); j < size; j++)
{
locations.put(u.topLevelDefinitions.get(j).toString(), s.getName());
}
}
}
else if (s.isSwcScriptOwner())
{
String location = ((SwcScript) s.getOwner()).getLibrary().getSwcLocation();
libraryNames.add(location);
if (locations != null)
{
for (int j = 0, size = u.topLevelDefinitions.size(); j < size; j++)
{
locations.put(u.topLevelDefinitions.get(j).toString(), location);
}
}
}
}
for (Source s : sources)
{
CompilationUnit u = (s == null) ? null : s.getCompilationUnit();
if (s == null)
{
continue;
}
if (s.isFileSpecOwner() || s.isSourceListOwner() || s.isSourcePathOwner() || s.isResourceBundlePathOwner())
{
Data d = new Data();
d.definitions = toArray(u.topLevelDefinitions);
d.prerequisites = toArray(u.inheritance, null, locations);
Set<Name> nameSet = new HashSet<Name>();
nameSet.addAll(u.namespaces);
nameSet.addAll(u.types);
nameSet.addAll(u.expressions);
d.dependencies = toArray(nameSet, new Set[] { u.extraClasses, u.resourceBundleHistory }, locations);
data.put(s.getName(), d);
}
}
}
private void processFrames(SimpleMovie movie)
{
int count = movie == null ? 0 : movie.frames.size();
assetNames = new String[count][];
definitionNames = new String[count][];
for (int i = 0; i < count; i++)
{
Frame f = movie.frames.get(i);
List<CompilationUnit> units = movie.getExportedUnitsByFrame(f);
List<String> aList = new ArrayList<String>(), dList = new ArrayList<String>();
for (int j = 0, size = units == null ? 0 : units.size(); j < size; j++)
{
CompilationUnit u = units.get(j);
Source s = u.getSource();
if (u.hasAssets())
{
for (Iterator k = u.getAssets().iterator(); k.hasNext(); )
{
Map.Entry e = (Map.Entry) k.next();
AssetInfo assetInfo = (AssetInfo) e.getValue();
VirtualFile path = assetInfo.getPath();
if (path != null)
{
String assetName = path.getName();
if (!aList.contains(assetName))
{
aList.add(assetName);
}
}
}
}
if (s.isFileSpecOwner() || s.isResourceBundlePathOwner() || s.isSourceListOwner() ||
s.isSourcePathOwner() || s.isSwcScriptOwner())
{
for (Iterator k = u.topLevelDefinitions.iterator(); k.hasNext(); )
{
String definitionName = k.next().toString();
dList.add(definitionName);
}
}
}
if (aList.size() > 0)
{
assetNames[i] = new String[aList.size()];
aList.toArray(assetNames[i]);
}
if (dList.size() > 0)
{
definitionNames[i] = new String[dList.size()];
dList.toArray(definitionNames[i]);
}
}
}
*/
private void processMessages(List<Message> messages)
{
if (messages != null && messages.size() > 0)
{
List<Message> filtered = new ArrayList<Message>();
for (int i = 0, length = messages.size(); i < length; i++)
{
Message m = messages.get(i);
if (m != null && !Message.INFO.equals(m.getLevel()))
{
filtered.add(m);
}
}
messages = filtered;
}
if (messages != null && messages.size() > 0)
{
this.messages = new Message[messages.size()];
for (int i = 0, length = this.messages.length; i < length; i++)
{
this.messages[i] = new GenericMessage(messages.get(i));
}
}
else
{
this.messages = null;
}
}
private String[] toArray(Set<String> set)
{
String[] a = new String[set == null ? 0 : set.size()];
int j = 0;
if (set != null)
{
for (String source : set)
{
a[j++] = source;
}
}
return a.length == 0 ? null : a;
}
/*
private String[] toArray(QNameList definitions)
{
String[] a = new String[definitions == null ? 0 : definitions.size()];
for (int i = 0; i < a.length; i++)
{
a[i] = definitions.get(i).toString();
}
return a.length == 0 ? null : a;
}
private String[] toArray(Set<Name> nameSet, Set[] sets, Map locations)
{
TreeSet<String> set = new TreeSet<String>();
for (Name name : nameSet)
{
String qName = null;
if (name instanceof QName && (locations == null || locations.containsKey(qName = name.toString())))
{
set.add(qName);
}
}
for (int i = 0, length = sets == null ? 0 : sets.length; i < length; i++)
{
if (sets[i] != null)
{
for (Object obj : sets[i])
{
if ((obj instanceof String) && (locations == null || locations.containsKey(obj)))
{
set.add((String)obj);
}
}
}
}
return toArray(set);
}
*/
static class Data
{
String[] definitions;
String[] prerequisites;
String[] dependencies;
}
}