/* * * 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 org.apache.flex.compiler.internal.targets; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Set; import org.apache.flex.compiler.common.DependencyType; import org.apache.flex.compiler.common.DependencyTypeSet; import org.apache.flex.compiler.config.RSLSettings; import org.apache.flex.compiler.exceptions.LibraryCircularDependencyException; import org.apache.flex.compiler.internal.projects.FlexProject; import org.apache.flex.compiler.targets.ITargetSettings; import org.apache.flex.swc.ISWC; /** * Class that contains information about RSLs used by a flex application SWF. * <p> * The information about RSLs is computed from {@link ITargetSettings} and * {@code FlexApplicationFrame1Info}. */ final class FlexRSLInfo { FlexRSLInfo(FlexApplicationFrame1Info frame1Info, FlexProject flexProject, ITargetSettings targetSettings) { this.frame1Info = frame1Info; this.flexProject = flexProject; this.targetSettings = targetSettings; requiredRSLs = new ArrayList<RSLSettings>(); placeholderRSLs = new ArrayList<RSLSettings>(); // The required RSLs are put in "requiredRSLs", the others are put in "placeholderRSLs". final List<RSLSettings> cdRSLs = targetSettings.getRuntimeSharedLibraryPath(); final Set<String> unusedRSLs = getUnusedRSLs(cdRSLs); for (RSLSettings rslSettings : cdRSLs) { if (unusedRSLs.contains(rslSettings.getLibraryFile().getAbsolutePath())) placeholderRSLs.add(rslSettings); else requiredRSLs.add(rslSettings); } } private final FlexApplicationFrame1Info frame1Info; private final ITargetSettings targetSettings; private final FlexProject flexProject; /** * {@link RSLSettings} for RSLs that must be loaded for the flex application * to load properly. */ final ArrayList<RSLSettings> requiredRSLs; /** * {@link RSLSettings} for RSLs were specified by * {@link ITargetSettings#getRuntimeSharedLibraryPath()}, but that were not * required by the flex application and were not marked as force load by * {@link RSLSettings#isForceLoad()}. */ final ArrayList<RSLSettings> placeholderRSLs; private Set<String> getUnusedRSLs(List<RSLSettings> cdRSLs) { if (!targetSettings.removeUnusedRuntimeSharedLibraryPaths()) return Collections.emptySet(); List<String> unusedRSLs = new LinkedList<String>(); // running list of unused rsls Set<String>loadedDownstreamRSLs = new HashSet<String>(); // loaded rsls downstream from first unused rsl boolean addDownstreamRSL = false; // Get unused RSLs and verify that there are no downstream RSLs that have // and inheritance dependency on them. for (RSLSettings info : cdRSLs) { String swcPath = info.getLibraryFile().getAbsolutePath(); // skip if the associated swc is filtered from our context. if (isSWCFiltered(swcPath)) continue; // skip loading the RSL if it does not contribute any classes to // the application and it is not forced. if (!frame1Info.contributingSWCs.contains(swcPath) && !info.isForceLoad()) { unusedRSLs.add(swcPath); addDownstreamRSL = true; } else if (addDownstreamRSL) { loadedDownstreamRSLs.add(swcPath); } } if (unusedRSLs.size() == 0) return Collections.emptySet(); Set<String> requiredInheritanceRSLs = filterBasedOnInheritanceDependencies(unusedRSLs, loadedDownstreamRSLs); unusedRSLs.removeAll(requiredInheritanceRSLs); if (unusedRSLs.size() == 0) return Collections.emptySet(); return new HashSet<String>(unusedRSLs); } /** * Create a set of swcs by filtering a list of swcs, choosing the swcs that * contain any inheritance dependencies from a set of filter swcs. * * @param swcPaths A list of swc paths to filter against the inheritance dependencies * of the swcPathFilters. * @param swcPathsFilter set of swc paths used as the inheritance dependendcy filter. * * @return subset of the swcPaths that contain inheritance dependencies * found in the swcPathsFilter. */ private Set<String> filterBasedOnInheritanceDependencies(List<String>swcPaths, Set<String>swcPathsFilter) { if (swcPathsFilter.isEmpty()) return Collections.emptySet(); // Loop over the filter swcs to see if they have any inheritance // dependencies on input swcs. Set<String> inheritanceDependencies = new HashSet<String>(swcPathsFilter.size()); DependencyTypeSet inheritanceDependency = DependencyTypeSet.of(DependencyType.INHERITANCE); // get the inheritance dependencies of all filter swcs for (String swcPath : swcPathsFilter) { Set<String> swcDependencies; try { swcDependencies = flexProject.computeLibraryDependencies(new File(swcPath), inheritanceDependency); } catch (LibraryCircularDependencyException e) { // Should never get a circular dependency when asking for // inheritance dependencies. RSLs could never be loaded in the // correct order. // Skip this swc and move on to the next. assert false : e.getMessage(); continue; } inheritanceDependencies.addAll(swcDependencies); } if (inheritanceDependencies.isEmpty()) return Collections.emptySet(); // check to see if any of the inheritance dependencies live in the // input swcs. // move thru the list backwards to we can handle the case where a // newly found swc can be used to test an upstream swc. Set<String> results = new HashSet<String>(); for (ListIterator<String> iter = swcPaths.listIterator(swcPaths.size()); iter.hasPrevious();) { String targetSWC = iter.previous(); if (inheritanceDependencies.contains(targetSWC)) { results.add(targetSWC); // add the found swc to the list of inheritance dependencies. if (iter.hasPrevious()) { try { inheritanceDependencies.addAll( flexProject.computeLibraryDependencies(new File(targetSWC), inheritanceDependency)); } catch (LibraryCircularDependencyException e) { // Should never get a circular dependency when asking for // inheritance dependencies. RSLs could never be loaded in the // correct order. // Skip this swc and move on to the next. assert false : e.getMessage(); } } } } return results; } /** * Check if this SWC should be ignored because its min supported version is * greater than the current compatibility version. * * @param swcPath * @return true if the SWC should be filtered, false otherwise. */ private boolean isSWCFiltered(String swcPath) { // if compatibility-version is not set then we won't be doing any filtering. if (flexProject.getCompatibilityVersion() == null) return false; int compatibilityVersion = flexProject.getCompatibilityVersion(); ISWC swc = flexProject.getWorkspace().getSWCManager().get(new File(swcPath)); if (compatibilityVersion < swc.getVersion().getFlexMinSupportedVersionInt()) { return true; } return false; } }