0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.apisupport.project.ui.customizer;
0043:
0044: import java.io.File;
0045: import java.io.IOException;
0046: import java.text.Collator;
0047: import java.util.ArrayList;
0048: import java.util.Arrays;
0049: import java.util.Collection;
0050: import java.util.Collections;
0051: import java.util.HashMap;
0052: import java.util.HashSet;
0053: import java.util.Iterator;
0054: import java.util.List;
0055: import java.util.Map;
0056: import java.util.Set;
0057: import java.util.SortedSet;
0058: import java.util.TreeMap;
0059: import java.util.TreeSet;
0060: import java.util.logging.Level;
0061: import java.util.logging.LogRecord;
0062: import java.util.logging.Logger;
0063: import javax.swing.SwingUtilities;
0064: import javax.swing.event.ListDataEvent;
0065: import javax.swing.event.ListDataListener;
0066: import org.netbeans.api.java.platform.JavaPlatform;
0067: import org.netbeans.api.project.Project;
0068: import org.netbeans.api.project.ProjectManager;
0069: import org.netbeans.api.project.ProjectUtils;
0070: import org.netbeans.modules.apisupport.project.EditableManifest;
0071: import org.netbeans.modules.apisupport.project.ManifestManager;
0072: import org.netbeans.modules.apisupport.project.NbModuleProject;
0073: import org.netbeans.modules.apisupport.project.spi.NbModuleProvider;
0074: import org.netbeans.modules.apisupport.project.ProjectXMLManager;
0075: import org.netbeans.modules.apisupport.project.SuiteProvider;
0076: import org.netbeans.modules.apisupport.project.Util;
0077: import org.netbeans.modules.apisupport.project.suite.SuiteProject;
0078: import org.netbeans.modules.apisupport.project.ui.customizer.CustomizerComponentFactory.DependencyListModel;
0079: import org.netbeans.modules.apisupport.project.ui.customizer.CustomizerComponentFactory.FriendListModel;
0080: import org.netbeans.modules.apisupport.project.ui.customizer.CustomizerComponentFactory.PublicPackagesTableModel;
0081: import org.netbeans.modules.apisupport.project.ui.customizer.CustomizerComponentFactory.RequiredTokenListModel;
0082: import org.netbeans.modules.apisupport.project.universe.LocalizedBundleInfo;
0083: import org.netbeans.modules.apisupport.project.universe.ModuleEntry;
0084: import org.netbeans.modules.apisupport.project.universe.ModuleList;
0085: import org.netbeans.modules.apisupport.project.universe.NbPlatform;
0086: import org.netbeans.spi.project.support.ant.AntProjectHelper;
0087: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
0088: import org.openide.DialogDisplayer;
0089: import org.openide.ErrorManager;
0090: import org.openide.NotifyDescriptor.Message;
0091: import org.openide.filesystems.FileObject;
0092: import org.openide.filesystems.FileUtil;
0093: import org.openide.util.NbBundle;
0094: import org.openide.util.Utilities;
0095:
0096: /**
0097: * Provides convenient access to a lot of NetBeans Module's properties.
0098: *
0099: * @author Martin Krauskopf
0100: */
0101: public final class SingleModuleProperties extends ModuleProperties {
0102:
0103: private static final String[] IDE_TOKENS = new String[] {
0104: "org.openide.modules.os.Windows", // NOI18N
0105: "org.openide.modules.os.Unix", // NOI18N
0106: "org.openide.modules.os.MacOSX", // NOI18N
0107: "org.openide.modules.os.PlainUnix", // NOI18N
0108: "org.openide.modules.os.OS2" // NOI18N
0109: };
0110:
0111: // property keys for project.properties
0112: public static final String BUILD_COMPILER_DEBUG = "build.compiler.debug"; // NOI18N
0113: public static final String BUILD_COMPILER_DEPRECATION = "build.compiler.deprecation"; // NOI18N
0114: public static final String CLUSTER_DIR = "cluster.dir"; // NOI18N
0115: public static final String IS_AUTOLOAD = "is.autoload"; // NOI18N
0116: public static final String IS_EAGER = "is.eager"; // NOI18N
0117: public static final String JAVAC_SOURCE = "javac.source"; // NOI18N
0118: public static final String JAVADOC_TITLE = "javadoc.title"; // NOI18N
0119: public static final String LICENSE_FILE = "license.file"; // NOI18N
0120: public static final String NBM_HOMEPAGE = "nbm.homepage"; // NOI18N
0121: public static final String NBM_MODULE_AUTHOR = "nbm.module.author"; // NOI18N
0122: public static final String NBM_NEEDS_RESTART = "nbm.needs.restart"; // NOI18N
0123: public static final String SPEC_VERSION_BASE = "spec.version.base"; // NOI18N
0124: /** @see "#66278" */
0125: public static final String JAVAC_COMPILERARGS = "javac.compilerargs"; // NOI18N
0126:
0127: static final String[] SOURCE_LEVELS = { "1.4", "1.5" }; // NOI18N
0128:
0129: private final static Map<String, String> DEFAULTS;
0130:
0131: private boolean majorReleaseVersionChanged;
0132: private boolean specificationVersionChanged;
0133: private boolean implementationVersionChange;
0134: private boolean providedTokensChanged;
0135: private boolean autoUpdateShowInClientChanged;
0136:
0137: private boolean moduleListRefreshNeeded;
0138:
0139: static {
0140: // setup defaults
0141: Map<String, String> map = new HashMap<String, String>();
0142: map.put(BUILD_COMPILER_DEBUG, "true"); // NOI18N
0143: map.put(BUILD_COMPILER_DEPRECATION, "true"); // NOI18N
0144: map.put(IS_AUTOLOAD, "false"); // NOI18N
0145: map.put(IS_EAGER, "false"); // NOI18N
0146: map.put(JAVAC_SOURCE, "1.4"); // NOI18N
0147: map.put(NBM_NEEDS_RESTART, "false"); // NOI18N
0148: DEFAULTS = Collections.unmodifiableMap(map);
0149: }
0150:
0151: // helpers for storing and retrieving real values currently stored on the disk
0152: private NbModuleProvider.NbModuleType moduleType;
0153: private SuiteProvider suiteProvider;
0154: private ProjectXMLManager projectXMLManager;
0155: private final LocalizedBundleInfo.Provider bundleInfoProvider;
0156: private LocalizedBundleInfo bundleInfo;
0157:
0158: // keeps current state of the user changes
0159: private String majorReleaseVersion;
0160: private String specificationVersion;
0161: private String implementationVersion;
0162: private String provTokensString;
0163: private SortedSet<String> requiredTokens;
0164: private Boolean autoUpdateShowInClient;
0165: private NbPlatform activePlatform;
0166: private NbPlatform originalPlatform;
0167: private JavaPlatform activeJavaPlatform;
0168: private boolean javaPlatformChanged; // #115989
0169:
0170: /** package name / selected */
0171: private SortedSet<String> availablePublicPackages;
0172:
0173: private String[] allTokens;
0174:
0175: /** Unmodifiable sorted set of all categories in the module's universe. */
0176: private SortedSet<String> modCategories;
0177:
0178: /** Unmodifiable sorted set of all dependencies in the module's universe. */
0179: private Set<ModuleDependency> universeDependencies;
0180:
0181: // models
0182: private PublicPackagesTableModel publicPackagesModel;
0183: private DependencyListModel dependencyListModel;
0184: private FriendListModel friendListModel;
0185: private RequiredTokenListModel requiredTokensListModel;
0186:
0187: public static final String NB_PLATFORM_PROPERTY = "nbPlatform"; // NOI18N
0188: public static final String JAVA_PLATFORM_PROPERTY = "nbjdk.active"; // NOI18N
0189: public static final String DEPENDENCIES_PROPERTY = "moduleDependencies"; // NOI18N
0190:
0191: /**
0192: * Returns an instance of SingleModuleProperties for the given project.
0193: */
0194: public static SingleModuleProperties getInstance(
0195: final NbModuleProject project) {
0196: SuiteProvider sp = project.getLookup().lookup(
0197: SuiteProvider.class);
0198: return new SingleModuleProperties(project.getHelper(), project
0199: .evaluator(), sp, Util.getModuleType(project), project
0200: .getLookup().lookup(LocalizedBundleInfo.Provider.class));
0201: }
0202:
0203: /**
0204: * Creates a new instance of SingleModuleProperties
0205: */
0206: SingleModuleProperties(AntProjectHelper helper,
0207: PropertyEvaluator evaluator, SuiteProvider sp,
0208: NbModuleProvider.NbModuleType moduleType,
0209: LocalizedBundleInfo.Provider bundleInfoProvider) {
0210: // XXX consider SingleModuleProperties(NbModuleProject) constructor. Life would be easier.
0211: super (helper, evaluator);
0212: this .bundleInfoProvider = bundleInfoProvider;
0213: refresh(moduleType, sp);
0214: }
0215:
0216: protected void refresh(NbModuleProvider.NbModuleType moduleType,
0217: SuiteProvider suiteProvider) {
0218: reloadProperties();
0219: // reset
0220: this .suiteProvider = suiteProvider;
0221: this .moduleType = moduleType;
0222: universeDependencies = null;
0223: modCategories = null;
0224: availablePublicPackages = null;
0225: dependencyListModel = null;
0226: friendListModel = null;
0227: requiredTokensListModel = null;
0228: projectXMLManager = null;
0229: if (isSuiteComponent()) {
0230: assert getSuiteDirectory() != null;
0231: ModuleList.refreshSuiteModuleList(getSuiteDirectory());
0232: }
0233: ManifestManager manifestManager = ManifestManager.getInstance(
0234: getManifestFile(), false);
0235: majorReleaseVersion = manifestManager.getReleaseVersion();
0236: specificationVersion = manifestManager
0237: .getSpecificationVersion();
0238: implementationVersion = manifestManager
0239: .getImplementationVersion();
0240: provTokensString = manifestManager.getProvidedTokensString();
0241: autoUpdateShowInClient = manifestManager
0242: .getAutoUpdateShowInClient();
0243: String nbDestDirS = getEvaluator().getProperty(
0244: "netbeans.dest.dir"); // NOI18N
0245: if (nbDestDirS != null) {
0246: originalPlatform = activePlatform = NbPlatform
0247: .getPlatformByDestDir(getHelper().resolveFile(
0248: nbDestDirS));
0249: }
0250: String activeJdk = getEvaluator().getProperty("nbjdk.active"); // NOI18N
0251: if (activeJdk != null) {
0252: activeJavaPlatform = ModuleProperties
0253: .findJavaPlatformByID(activeJdk); // NOI18N
0254: } else {
0255: String activeJdkHome = getEvaluator().getProperty(
0256: "nbjdk.home"); // NOI18N
0257: activeJavaPlatform = ModuleProperties
0258: .findJavaPlatformByLocation(activeJdkHome);
0259: }
0260: javaPlatformChanged = false;
0261: getPublicPackagesModel().reloadData(loadPublicPackages());
0262: requiredTokens = Collections
0263: .unmodifiableSortedSet(new TreeSet<String>(Arrays
0264: .asList(manifestManager.getRequiredTokens())));
0265: bundleInfo = bundleInfoProvider.getLocalizedBundleInfo();
0266: if (bundleInfo != null) {
0267: try {
0268: bundleInfo.reload();
0269: } catch (IOException ioe) {
0270: ErrorManager.getDefault().notify(ioe);
0271: }
0272: }
0273: firePropertiesRefreshed();
0274: }
0275:
0276: void libraryWrapperAdded() {
0277: // presuambly we do not need to reset anything else
0278: universeDependencies = null;
0279: }
0280:
0281: Map<String, String> getDefaultValues() {
0282: return DEFAULTS;
0283: }
0284:
0285: LocalizedBundleInfo getBundleInfo() {
0286: return bundleInfo;
0287: }
0288:
0289: // ---- READ ONLY start
0290:
0291: /** Returns code name base of the module this instance managing. */
0292: String getCodeNameBase() {
0293: return getProjectXMLManager().getCodeNameBase();
0294: }
0295:
0296: String getJarFile() {
0297: return getHelper().resolveFile(
0298: getEvaluator().evaluate("${cluster}/${module.jar}"))
0299: .getAbsolutePath(); // NOI18N
0300: }
0301:
0302: String getSuiteDirectoryPath() {
0303: return getSuiteDirectory() != null ? getSuiteDirectory()
0304: .getPath() : null;
0305: }
0306:
0307: File getSuiteDirectory() {
0308: return suiteProvider != null ? suiteProvider
0309: .getSuiteDirectory() : null;
0310: }
0311:
0312: /** Call only for suite component modules. */
0313: SuiteProject getSuite() {
0314: assert isSuiteComponent();
0315: SuiteProject suite = null;
0316: try {
0317: FileObject suiteDir = FileUtil
0318: .toFileObject(getSuiteDirectory());
0319: if (suiteDir != null) {
0320: suite = (SuiteProject) ProjectManager.getDefault()
0321: .findProject(suiteDir);
0322: }
0323: } catch (IOException e) {
0324: Util.err.notify(ErrorManager.INFORMATIONAL, e);
0325: }
0326: return suite;
0327: }
0328:
0329: // ---- READ ONLY end
0330:
0331: /** Check whether the active platform is valid. */
0332: boolean isActivePlatformValid() {
0333: NbPlatform plaf = getActivePlatform();
0334: return plaf == null || plaf.isValid();
0335: }
0336:
0337: /**
0338: * Returns currently set platform. i.e. platform set in the
0339: * <em>Libraries</em> panel. Note that it could be <code>null</code> for
0340: * NetBeans.org modules.
0341: */
0342: NbPlatform getActivePlatform() {
0343: if (moduleType != NbModuleProvider.NETBEANS_ORG
0344: && activePlatform == null) {
0345: ModuleProperties.reportLostPlatform(activePlatform);
0346: activePlatform = NbPlatform.getDefaultPlatform();
0347: }
0348: return activePlatform;
0349: }
0350:
0351: void setActivePlatform(NbPlatform newPlaf) {
0352: if (this .activePlatform != newPlaf) {
0353: NbPlatform oldPlaf = this .activePlatform;
0354: this .activePlatform = newPlaf;
0355: this .dependencyListModel = null;
0356: this .universeDependencies = null;
0357: this .modCategories = null;
0358: firePropertyChange(NB_PLATFORM_PROPERTY, oldPlaf, newPlaf);
0359: }
0360: }
0361:
0362: JavaPlatform getActiveJavaPlatform() {
0363: return activeJavaPlatform;
0364: }
0365:
0366: void setActiveJavaPlatform(JavaPlatform nue) {
0367: JavaPlatform old = activeJavaPlatform;
0368: if (nue != old) {
0369: activeJavaPlatform = nue;
0370: firePropertyChange(JAVA_PLATFORM_PROPERTY, old, nue);
0371: javaPlatformChanged = true;
0372: }
0373: }
0374:
0375: String getMajorReleaseVersion() {
0376: return majorReleaseVersion;
0377: }
0378:
0379: void setMajorReleaseVersion(String ver) {
0380: if (!Utilities.compareObjects(majorReleaseVersion, ver)) {
0381: majorReleaseVersion = ver;
0382: majorReleaseVersionChanged = true;
0383: }
0384: }
0385:
0386: String getSpecificationVersion() {
0387: return specificationVersion;
0388: }
0389:
0390: void setSpecificationVersion(String ver) {
0391: if (!Utilities.compareObjects(specificationVersion, ver)) {
0392: specificationVersion = ver;
0393: specificationVersionChanged = true;
0394: }
0395: }
0396:
0397: String getImplementationVersion() {
0398: return implementationVersion;
0399: }
0400:
0401: void setImplementationVersion(String ver) {
0402: if (!Utilities.compareObjects(implementationVersion, ver)) {
0403: implementationVersion = ver;
0404: implementationVersionChange = true;
0405: }
0406: }
0407:
0408: String getProvidedTokens() {
0409: return provTokensString;
0410: }
0411:
0412: void setProvidedTokens(String tokens) {
0413: if (!Utilities.compareObjects(provTokensString, tokens)) {
0414: provTokensString = tokens;
0415: providedTokensChanged = true;
0416: }
0417: }
0418:
0419: public Boolean getAutoUpdateShowInClient() {
0420: return autoUpdateShowInClient;
0421: }
0422:
0423: public void setAutoUpdateShowInClient(Boolean autoUpdateShowInClient) {
0424: if (!Utilities.compareObjects(this .autoUpdateShowInClient,
0425: autoUpdateShowInClient)) {
0426: this .autoUpdateShowInClient = autoUpdateShowInClient;
0427: autoUpdateShowInClientChanged = true;
0428: }
0429: }
0430:
0431: boolean isStandalone() {
0432: return moduleType == NbModuleProvider.STANDALONE;
0433: }
0434:
0435: boolean isNetBeansOrg() {
0436: return moduleType == NbModuleProvider.NETBEANS_ORG;
0437: }
0438:
0439: boolean isSuiteComponent() {
0440: return moduleType == NbModuleProvider.SUITE_COMPONENT;
0441: }
0442:
0443: public void setModuleListRefreshNeeded(
0444: boolean moduleListRefreshNeeded) {
0445: this .moduleListRefreshNeeded = moduleListRefreshNeeded;
0446: }
0447:
0448: boolean isModuleListRefreshNeeded() {
0449: return moduleListRefreshNeeded;
0450: }
0451:
0452: boolean dependingOnImplDependency() {
0453: DependencyListModel depsModel = getDependenciesListModel();
0454: if (depsModel == CustomizerComponentFactory.INVALID_DEP_LIST_MODEL) {
0455: return false;
0456: }
0457: Set<ModuleDependency> deps = depsModel.getDependencies();
0458: for (Iterator it = deps.iterator(); it.hasNext();) {
0459: ModuleDependency dep = (ModuleDependency) it.next();
0460: if (dep.hasImplementationDepedendency()) {
0461: return true;
0462: }
0463: }
0464: return false;
0465: }
0466:
0467: private ProjectXMLManager getProjectXMLManager() {
0468: if (projectXMLManager == null) {
0469: try {
0470: projectXMLManager = ProjectXMLManager
0471: .getInstance(getProjectDirectoryFile());
0472: } catch (IOException e) {
0473: assert false : e;
0474: }
0475: }
0476: return projectXMLManager;
0477: }
0478:
0479: /**
0480: * Returns list model of module's dependencies regarding the currently
0481: * selected platform.
0482: */
0483: DependencyListModel getDependenciesListModel() {
0484: if (dependencyListModel == null) {
0485: if (isActivePlatformValid()) {
0486: try {
0487: dependencyListModel = new DependencyListModel(
0488: getProjectXMLManager()
0489: .getDirectDependencies(
0490: getActivePlatform()), true);
0491: // add listener and fire DEPENDENCIES_PROPERTY when deps are changed
0492: dependencyListModel
0493: .addListDataListener(new ListDataListener() {
0494: public void contentsChanged(
0495: ListDataEvent e) {
0496: firePropertyChange(
0497: DEPENDENCIES_PROPERTY,
0498: null,
0499: getDependenciesListModel());
0500: }
0501:
0502: public void intervalAdded(
0503: ListDataEvent e) {
0504: contentsChanged(null);
0505: }
0506:
0507: public void intervalRemoved(
0508: ListDataEvent e) {
0509: contentsChanged(null);
0510: }
0511: });
0512: } catch (IOException ioe) {
0513: ErrorManager.getDefault().notify(ioe);
0514: dependencyListModel = CustomizerComponentFactory
0515: .getInvalidDependencyListModel();
0516: }
0517: } else {
0518: dependencyListModel = CustomizerComponentFactory
0519: .getInvalidDependencyListModel();
0520: }
0521: }
0522: return dependencyListModel;
0523: }
0524:
0525: /**
0526: * Returns a set of available {@link ModuleDependency modules dependencies}
0527: * in the module's universe according to the currently selected {@link
0528: * #getActivePlatform() platform}.<p>
0529: *
0530: * <strong>Note:</strong> Don't call this method from EDT, since it may be
0531: * really slow. The {@link AssertionError} will be thrown if you try to do
0532: * so.
0533: *
0534: * @param filterExcludedModules if <code>true</code> and this module is a
0535: * suite component, modules excluded from the suite's module list
0536: * will be excluded from the returned set.
0537: * @param apiProvidersOnly if <code>true</code> only modules which provide
0538: * public packages and have friendly relationship with this module
0539: * will be included in the returned set
0540: */
0541: Set<ModuleDependency> getUniverseDependencies(
0542: final boolean filterExcludedModules,
0543: final boolean apiProvidersOnly) {
0544: assert !SwingUtilities.isEventDispatchThread() : "SingleModuleProperties.getUniverseDependencies() cannot be called from EDT"; // NOI18N
0545: if (universeDependencies == null) {
0546: reloadModuleListInfo();
0547: }
0548: if (universeDependencies == null) {
0549: // Broken platform.
0550: return Collections.emptySet();
0551: }
0552: Set<ModuleDependency> result = new HashSet<ModuleDependency>(
0553: universeDependencies);
0554: if (filterExcludedModules && isSuiteComponent()) {
0555: SuiteProject suite = getSuite();
0556: if (suite == null) {
0557: DialogDisplayer
0558: .getDefault()
0559: .notify(
0560: new Message(
0561: NbBundle
0562: .getMessage(
0563: SingleModuleProperties.class,
0564: "SingleModuleProperties.incorrectSuite",
0565: getSuiteDirectoryPath(),
0566: getProjectDisplayName()),
0567: Message.WARNING_MESSAGE));
0568: return Collections.emptySet();
0569: }
0570: String[] disableModules = SuiteProperties.getArrayProperty(
0571: suite.getEvaluator(),
0572: SuiteProperties.DISABLED_MODULES_PROPERTY);
0573: String[] enableClusters = SuiteProperties.getArrayProperty(
0574: suite.getEvaluator(),
0575: SuiteProperties.ENABLED_CLUSTERS_PROPERTY);
0576: String[] disableClusters = SuiteProperties
0577: .getArrayProperty(suite.getEvaluator(),
0578: SuiteProperties.DISABLED_CLUSTERS_PROPERTY);
0579: String suiteClusterProp = getEvaluator().getProperty(
0580: "cluster"); // NOI18N
0581: File suiteClusterDir = suiteClusterProp != null ? getHelper()
0582: .resolveFile(suiteClusterProp)
0583: : null;
0584: for (Iterator<ModuleDependency> it = result.iterator(); it
0585: .hasNext();) {
0586: ModuleDependency dep = it.next();
0587: ModuleEntry me = dep.getModuleEntry();
0588: if (me.getClusterDirectory().equals(suiteClusterDir)) {
0589: // #72124: do not filter other modules in the same suite.
0590: continue;
0591: }
0592: if (isExcluded(me, disableModules, enableClusters,
0593: disableClusters)) {
0594: it.remove();
0595: }
0596: }
0597: }
0598: if (apiProvidersOnly) { // remove module without public/friend API
0599: for (Iterator<ModuleDependency> it = result.iterator(); it
0600: .hasNext();) {
0601: ModuleDependency dep = it.next();
0602: ModuleEntry me = dep.getModuleEntry();
0603: if (me.getPublicPackages().length == 0
0604: || !me.isDeclaredAsFriend(getCodeNameBase())) {
0605: it.remove();
0606: }
0607: }
0608: }
0609: return Collections.unmodifiableSet(result);
0610: }
0611:
0612: /**
0613: * Delegates to {@link #getUniverseDependencies(boolean, boolean)} with
0614: * <code>false</code> as a second parameter.
0615: */
0616: Set<ModuleDependency> getUniverseDependencies(
0617: final boolean filterExcludedModules) {
0618: return getUniverseDependencies(filterExcludedModules, false);
0619: }
0620:
0621: private static boolean isExcluded(final ModuleEntry me,
0622: final String[] disableModules,
0623: final String[] enableClusters,
0624: final String[] disableClusters) {
0625: if (Arrays.binarySearch(disableModules, me.getCodeNameBase()) >= 0) {
0626: return true;
0627: }
0628: if (enableClusters.length != 0
0629: && Arrays.binarySearch(enableClusters, me
0630: .getClusterDirectory().getName()) < 0) {
0631: return true;
0632: }
0633: if (enableClusters.length == 0
0634: && Arrays.binarySearch(disableClusters, me
0635: .getClusterDirectory().getName()) >= 0) {
0636: return true;
0637: }
0638: return false;
0639: }
0640:
0641: /**
0642: * Returns sorted arrays of CNBs of available friends for this module.
0643: */
0644: String[] getAvailableFriends() {
0645: SortedSet<String> set = new TreeSet<String>();
0646: if (isSuiteComponent()) {
0647: for (Iterator it = SuiteUtils.getSubProjects(getSuite())
0648: .iterator(); it.hasNext();) {
0649: Project prj = (Project) it.next();
0650: String cnb = ProjectUtils.getInformation(prj).getName();
0651: if (!getCodeNameBase().equals(cnb)) {
0652: set.add(cnb);
0653: }
0654: }
0655: } else if (isNetBeansOrg()) {
0656: Set<ModuleDependency> deps = getUniverseDependencies(false);
0657: for (Iterator it = deps.iterator(); it.hasNext();) {
0658: ModuleDependency dep = (ModuleDependency) it.next();
0659: set.add(dep.getModuleEntry().getCodeNameBase());
0660: }
0661: } // else standalone module - leave empty (see the UI spec)
0662: return set.toArray(new String[set.size()]);
0663: }
0664:
0665: FriendListModel getFriendListModel() {
0666: if (friendListModel == null) {
0667: friendListModel = new FriendListModel(
0668: getProjectXMLManager().getFriends());
0669: }
0670: return friendListModel;
0671: }
0672:
0673: RequiredTokenListModel getRequiredTokenListModel() {
0674: if (requiredTokensListModel == null) {
0675: requiredTokensListModel = new RequiredTokenListModel(
0676: requiredTokens);
0677: }
0678: return requiredTokensListModel;
0679: }
0680:
0681: // XXX should be probably moved into ModuleList
0682: String[] getAllTokens() {
0683: if (allTokens == null) {
0684: try {
0685: SortedSet<String> provTokens = new TreeSet<String>();
0686: provTokens.addAll(Arrays.asList(IDE_TOKENS));
0687: for (Iterator it = getModuleList().getAllEntriesSoft()
0688: .iterator(); it.hasNext();) {
0689: ModuleEntry me = (ModuleEntry) it.next();
0690: provTokens.addAll(Arrays.asList(me
0691: .getProvidedTokens()));
0692: }
0693: String[] result = new String[provTokens.size()];
0694: return provTokens.toArray(result);
0695: } catch (IOException e) {
0696: allTokens = new String[0];
0697: ErrorManager.getDefault().notify(
0698: ErrorManager.INFORMATIONAL, e);
0699: }
0700: }
0701: return allTokens;
0702: }
0703:
0704: PublicPackagesTableModel getPublicPackagesModel() {
0705: if (publicPackagesModel == null) {
0706: publicPackagesModel = new PublicPackagesTableModel(
0707: loadPublicPackages());
0708: }
0709: return publicPackagesModel;
0710: }
0711:
0712: /** Loads a map of package-isSelected entries. */
0713: private Map<String, Boolean> loadPublicPackages() {
0714: Collection<String> selectedPackages = getSelectedPackages();
0715: Map<String, Boolean> publicPackages = new TreeMap<String, Boolean>();
0716: for (Iterator<String> it = getAvailablePublicPackages()
0717: .iterator(); it.hasNext();) {
0718: String pkg = it.next();
0719: publicPackages.put(pkg, Boolean.valueOf(selectedPackages
0720: .contains(pkg)));
0721: }
0722: return publicPackages;
0723: }
0724:
0725: private Collection<String> getSelectedPackages() {
0726: Collection<String> sPackages = new HashSet<String>();
0727: ManifestManager.PackageExport[] pexports = getProjectXMLManager()
0728: .getPublicPackages();
0729: for (int i = 0; i < pexports.length; i++) {
0730: ManifestManager.PackageExport pexport = pexports[i];
0731: if (pexport.isRecursive()) {
0732: for (Iterator it = getAvailablePublicPackages()
0733: .iterator(); it.hasNext();) {
0734: String p = (String) it.next();
0735: if (p.startsWith(pexport.getPackage())) {
0736: sPackages.add(p);
0737: }
0738: }
0739: } else {
0740: sPackages.add(pexport.getPackage());
0741: }
0742: }
0743: return sPackages;
0744: }
0745:
0746: /**
0747: * Returns set of all available public packages for the project.
0748: */
0749: Set<String> getAvailablePublicPackages() {
0750: if (availablePublicPackages == null) {
0751: availablePublicPackages = Util
0752: .scanProjectForPackageNames(getProjectDirectoryFile());
0753: }
0754: return availablePublicPackages;
0755: }
0756:
0757: @Override
0758: void storeProperties() throws IOException {
0759: super .storeProperties();
0760:
0761: // Store chnages in manifest
0762: storeManifestChanges();
0763:
0764: // store localized info
0765: if (bundleInfo != null && bundleInfo.isModified()) {
0766: bundleInfo.store();
0767: } // XXX else ignore for now but we could save into some default location
0768:
0769: // Store project.xml changes
0770: // store module dependencies
0771: DependencyListModel dependencyModel = getDependenciesListModel();
0772: if (dependencyModel.isChanged()) {
0773: Set<ModuleDependency> depsToSave = new TreeSet<ModuleDependency>(
0774: dependencyModel.getDependencies());
0775:
0776: // process removed modules
0777: depsToSave.removeAll(dependencyModel
0778: .getRemovedDependencies());
0779:
0780: // process added modules
0781: depsToSave.addAll(dependencyModel.getAddedDependencies());
0782:
0783: // process edited modules
0784: for (Map.Entry<ModuleDependency, ModuleDependency> entry : dependencyModel
0785: .getEditedDependencies().entrySet()) {
0786: depsToSave.remove(entry.getKey());
0787: depsToSave.add(entry.getValue());
0788: }
0789:
0790: logNetBeansAPIUsage("DEPENDENCIES", dependencyModel
0791: .getDependencies()); // NOI18N
0792:
0793: getProjectXMLManager().replaceDependencies(depsToSave);
0794: }
0795: String[] friends = getFriendListModel().getFriends();
0796: String[] publicPkgs = getPublicPackagesModel()
0797: .getSelectedPackages();
0798: if (getPublicPackagesModel().isChanged()
0799: || getFriendListModel().isChanged()) {
0800: if (friends.length > 0) { // store friends packages
0801: getProjectXMLManager().replaceFriends(friends,
0802: publicPkgs);
0803: } else { // store public packages
0804: getProjectXMLManager()
0805: .replacePublicPackages(publicPkgs);
0806: }
0807: setModuleListRefreshNeeded(true);
0808: }
0809:
0810: if (isStandalone()) {
0811: ModuleProperties.storePlatform(getHelper(),
0812: getActivePlatform());
0813: if (javaPlatformChanged) {
0814: ModuleProperties.storeJavaPlatform(getHelper(),
0815: getEvaluator(), getActiveJavaPlatform(), false);
0816: }
0817: } else if (isNetBeansOrg() && javaPlatformChanged) {
0818: ModuleProperties.storeJavaPlatform(getHelper(),
0819: getEvaluator(), getActiveJavaPlatform(), true);
0820: }
0821: }
0822:
0823: /** UI Logger for apisupport */
0824: static final Logger UI_LOG = Logger
0825: .getLogger("org.netbeans.ui.apisupport"); // NOI18N
0826:
0827: /** Sends info to UI handler about NetBeans APIs in use
0828: */
0829: private static void logNetBeansAPIUsage(String msg,
0830: Collection<ModuleDependency> deps) {
0831: List<String> cnbs = new ArrayList<String>();
0832: for (ModuleDependency moduleDependency : deps) {
0833: String cnb = moduleDependency.getModuleEntry()
0834: .getCodeNameBase();
0835: // observe just NetBeans API module usage
0836: if (cnb.startsWith("org.openide")
0837: || cnb.startsWith("org.netbeans")) { // NOI18N
0838: cnbs.add(cnb);
0839: }
0840: }
0841:
0842: if (cnbs.isEmpty()) {
0843: return;
0844: }
0845:
0846: LogRecord rec = new LogRecord(Level.CONFIG, msg);
0847: rec.setParameters(cnbs.toArray(new String[0]));
0848: rec.setResourceBundleName(SingleModuleProperties.class
0849: .getPackage().getName()
0850: + ".Bundle"); // NOI18N
0851: rec.setResourceBundle(NbBundle
0852: .getBundle(SingleModuleProperties.class));
0853: rec.setLoggerName(UI_LOG.getName());
0854: UI_LOG.log(rec);
0855: }
0856:
0857: /**
0858: * Store appropriately properties regarding the manifest file.
0859: */
0860: private void storeManifestChanges() throws IOException {
0861: FileObject manifestFO = FileUtil
0862: .toFileObject(getManifestFile());
0863: EditableManifest em;
0864: if (manifestFO != null) {
0865: em = Util.loadManifest(manifestFO);
0866: } else { // manifest doesn't exist yet
0867: em = new EditableManifest();
0868: manifestFO = FileUtil.createData(getHelper()
0869: .getProjectDirectory(), "manifest.mf"); // NOI18N
0870: }
0871: boolean changed = false;
0872: if (majorReleaseVersionChanged) {
0873: String module = "".equals(getMajorReleaseVersion()) ? getCodeNameBase()
0874: : getCodeNameBase() + '/'
0875: + getMajorReleaseVersion();
0876: setManifestAttribute(em, ManifestManager.OPENIDE_MODULE,
0877: module);
0878: changed = true;
0879: }
0880: if (specificationVersionChanged) {
0881: setManifestAttribute(
0882: em,
0883: ManifestManager.OPENIDE_MODULE_SPECIFICATION_VERSION,
0884: getSpecificationVersion());
0885: changed = true;
0886: }
0887: if (implementationVersionChange) {
0888: setManifestAttribute(
0889: em,
0890: ManifestManager.OPENIDE_MODULE_IMPLEMENTATION_VERSION,
0891: getImplementationVersion());
0892: changed = true;
0893: }
0894: if (providedTokensChanged) {
0895: setManifestAttribute(em,
0896: ManifestManager.OPENIDE_MODULE_PROVIDES,
0897: getProvidedTokens());
0898: changed = true;
0899: }
0900: if (getRequiredTokenListModel().isChanged()) {
0901: String[] reqTokens = getRequiredTokenListModel()
0902: .getTokens();
0903: StringBuffer result = new StringBuffer(
0904: reqTokens.length > 1 ? "\n " : ""); // NOI18N
0905: for (int i = 0; i < reqTokens.length; i++) {
0906: if (i != 0) {
0907: result.append(",\n "); // NOI18N
0908: }
0909: result.append(reqTokens[i]);
0910: }
0911: setManifestAttribute(em,
0912: ManifestManager.OPENIDE_MODULE_REQUIRES, result
0913: .toString());
0914: changed = true;
0915: }
0916: if (autoUpdateShowInClientChanged) {
0917: setManifestAttribute(
0918: em,
0919: ManifestManager.AUTO_UPDATE_SHOW_IN_CLIENT,
0920: autoUpdateShowInClient != null ? autoUpdateShowInClient
0921: .toString()
0922: : "");
0923: changed = true;
0924: }
0925: if (changed) {
0926: Util.storeManifest(manifestFO, em);
0927: }
0928: }
0929:
0930: // XXX should be something similar provided be EditableManifest?
0931: private void setManifestAttribute(EditableManifest em, String key,
0932: String value) {
0933: assert value != null;
0934: if ("".equals(value)) {
0935: if (em.getAttribute(key, null) != null) {
0936: em.removeAttribute(key, null);
0937: }
0938: } else {
0939: em.setAttribute(key, value, null);
0940: }
0941: }
0942:
0943: // package provide for unit test
0944: File getManifestFile() {
0945: return getHelper().resolveFile(
0946: getEvaluator().getProperty("manifest.mf")); // NOI18N
0947: }
0948:
0949: /**
0950: * Returns a set of all available categories in the module's universe
0951: * according to the currently selected platform ({@link
0952: * #getActivePlatform()})<p>
0953: * <strong>Note:</strong> Don't call this method from EDT, since it may be
0954: * really slow. The {@link AssertionError} will be thrown if you try to do
0955: * so.
0956: */
0957: SortedSet getModuleCategories() {
0958: assert !SwingUtilities.isEventDispatchThread() : "SingleModuleProperties.getModuleCategories() cannot be called from EDT"; // NOI18N
0959: if (modCategories == null && !reloadModuleListInfo()) {
0960: return new TreeSet();
0961: }
0962: return modCategories;
0963: }
0964:
0965: /**
0966: * Prepare all ModuleDependencies from this module's universe. Also prepare
0967: * all categories. <strong>Package-private only for unit tests.</strong>
0968: */
0969: boolean reloadModuleListInfo() {
0970: assert !SwingUtilities.isEventDispatchThread() : "SingleModuleProperties.reloadModuleListInfo() cannot be called from EDT"; // NOI18N
0971: if (isActivePlatformValid()) {
0972: try {
0973: SortedSet<String> allCategories = new TreeSet<String>(
0974: Collator.getInstance());
0975: Set<ModuleDependency> allDependencies = new HashSet<ModuleDependency>();
0976: for (Iterator it = getModuleList().getAllEntriesSoft()
0977: .iterator(); it.hasNext();) {
0978: ModuleEntry me = (ModuleEntry) it.next();
0979: if (!me.getCodeNameBase().equals(getCodeNameBase())) {
0980: allDependencies.add(new ModuleDependency(me));
0981: }
0982: String cat = me.getCategory();
0983: if (cat != null) {
0984: allCategories.add(cat);
0985: }
0986: }
0987: modCategories = Collections
0988: .unmodifiableSortedSet(allCategories);
0989: universeDependencies = Collections
0990: .unmodifiableSet(allDependencies);
0991: return true;
0992: } catch (IOException ioe) {
0993: ErrorManager.getDefault().notify(ioe);
0994: }
0995: }
0996: return false;
0997: }
0998:
0999: /**
1000: * Helper method to get the <code>ModuleList</code> for the project this
1001: * instance manage. <strong>Package-private only for unit tests.</strong>
1002: */
1003: ModuleList getModuleList() throws IOException {
1004: if (getActivePlatform() != this .originalPlatform) {
1005: try {
1006: return ModuleList.getModuleList(
1007: getProjectDirectoryFile(), getActivePlatform()
1008: .getDestDir());
1009: } catch (IOException x) {
1010: // #69029: maybe invalidated platform? Try the default platform instead.
1011: Logger
1012: .getLogger(
1013: SingleModuleProperties.class.getName())
1014: .log(Level.FINE, null, x);
1015: NbPlatform p = NbPlatform.getDefaultPlatform();
1016: return ModuleList.getModuleList(
1017: getProjectDirectoryFile(), p != null ? p
1018: .getDestDir() : null);
1019: }
1020: } else {
1021: return ModuleList.getModuleList(getProjectDirectoryFile());
1022: }
1023: }
1024:
1025: /**
1026: * Just use a combination of evaluator and resolver. May return
1027: * <code>null</code> if evaluating fails.
1028: */
1029: File evaluateFile(final String currentLicence) {
1030: String evaluated = getEvaluator().evaluate(currentLicence);
1031: return evaluated == null ? null : getHelper().resolveFile(
1032: evaluated);
1033: }
1034:
1035: Project getProject() {
1036: Project p = null;
1037: try {
1038: p = ProjectManager.getDefault().findProject(
1039: getHelper().getProjectDirectory());
1040: } catch (IOException e) {
1041: assert false : e;
1042: }
1043: return p;
1044: }
1045:
1046: }
|