001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.j2me.cdc.platform;
043:
044: import java.io.File;
045: import java.lang.ref.Reference;
046: import java.lang.ref.WeakReference;
047: import java.net.URL;
048: import java.util.ArrayList;
049: import java.util.Collection;
050: import java.util.Collections;
051: import java.util.Iterator;
052: import java.util.List;
053: import java.util.Map;
054: import java.util.Properties;
055: import org.netbeans.api.java.classpath.ClassPath;
056: import org.netbeans.api.java.platform.JavaPlatform;
057: import org.netbeans.api.java.platform.Specification;
058: import org.netbeans.modules.j2me.cdc.platform.platformdefinition.Util;
059: import org.netbeans.spi.java.classpath.PathResourceImplementation;
060: import org.netbeans.spi.java.classpath.support.ClassPathSupport;
061: import org.netbeans.spi.project.support.ant.PropertyUtils;
062: import org.openide.filesystems.FileObject;
063: import org.openide.filesystems.FileStateInvalidException;
064: import org.openide.filesystems.FileUtil;
065: import org.openide.filesystems.Repository;
066: import org.openide.filesystems.URLMapper;
067: import org.openide.modules.SpecificationVersion;
068: import org.openide.util.Lookup;
069:
070: /**
071: * Implementation of the JavaPlatform API class, which serves proper
072: * bootstrap classpath information.
073: */
074: public class CDCPlatform extends JavaPlatform {
075:
076: public static final String PROP_ANT_NAME = "antName"; //NOI18N
077: public static final String PLATFORM_CDC = "cdc"; //NOI18N
078:
079: protected static final String PLAT_PROP_ANT_NAME = "platform.ant.name"; //NOI18N
080: public static final String PLATFORM_STRING_PREFIX = "${platform.home}/"; // NOI18N
081:
082: // protected static final String SYSPROP_BOOT_CLASSPATH = "sun.boot.class.path"; // NOI18N
083: // protected static final String SYSPROP_JAVA_CLASS_PATH = "java.class.path"; // NOI18N
084: // protected static final String SYSPROP_JAVA_EXT_PATH = "java.ext.dirs"; //NOI18N
085:
086: public static String PROP_EXEC_MAIN = "main";
087: public static String PROP_EXEC_XLET = "xlet";
088: public static String PROP_EXEC_APPLET = "applet";
089:
090: /**
091: * Holds the properties of the platform
092: */
093: private Properties properties;
094:
095: /**
096: * Holds the display name of the platform
097: */
098: private String displayName;
099:
100: /**
101: * String type of VM
102: */
103: private String type;
104:
105: /**
106: * String supported class version
107: */
108: private String classVersion;
109:
110: /**
111: * List<URL>
112: */
113: private ClassPath sources;
114:
115: /**
116: * List<URL>
117: */
118: private List<URL> javadoc;
119:
120: /**
121: * List<FileObject>
122: */
123: private List<URL> installFolders;
124:
125: /**
126: * List of supported devices
127: */
128: private CDCDevice[] devices;
129:
130: private boolean fatJar;
131:
132: /**
133: * Holds bootstrap libraries for the platform
134: */
135: Reference<ClassPath> bootstrap = new WeakReference<ClassPath>(null);
136: /**
137: * Holds standard libraries of the platform
138: */
139: Reference<ClassPath> standardLibs = new WeakReference<ClassPath>(
140: null);
141:
142: /**
143: * Holds the specification of the platform
144: */
145: private Specification spec;
146:
147: /**
148: * @param dispName display name for platfrom
149: * @param antName ant name for platform
150: * @param type type of platform (semc, nokiaS80, savaje, ricoh)
151: * @param classVersion maximum class version supported
152: * @param installFolders where the platfrom is installed
153: * @param sources list of FileObject with source folders for platform
154: * @param javadoc list of FileObject with javadoc folders for platform (note, top level folders, where index.html is located or entry in zip file)
155: * @param devices array of CDCDevices
156: */
157: public CDCPlatform(String dispName, String antName, String type,
158: String classVersion, List<URL> installFolders,
159: List<URL> sources, List<URL> javadoc, CDCDevice[] devices,
160: boolean fatJar) {
161: super ();
162: assert classVersion != null;
163: this .displayName = dispName;
164: this .type = type;
165: this .classVersion = classVersion;
166: this .devices = devices;
167: this .fatJar = fatJar;
168:
169: if (installFolders != null) {
170: this .installFolders = installFolders; //No copy needed, called from this module => safe
171: }
172: this .sources = createClassPath(sources);
173: if (javadoc != null) {
174: this .javadoc = Collections.unmodifiableList(javadoc); //No copy needed, called from this module => safe
175: } else {
176: this .javadoc = Collections.EMPTY_LIST;
177: }
178: properties = new Properties();
179: properties.put(PLAT_PROP_ANT_NAME, antName);
180: }
181:
182: /**
183: * @return a descriptive, human-readable name of the platform
184: */
185: public String getDisplayName() {
186: return displayName;
187: }
188:
189: /**
190: * Alters the human-readable name of the platform
191: * @param name the new display name
192: */
193: public void setDisplayName(String name) {
194: this .displayName = name;
195: firePropertyChange(PROP_DISPLAY_NAME, null, null); // NOI18N
196: }
197:
198: /**
199: * Alters the human-readable name of the platform without firing
200: * events. This method is an internal contract to allow lazy creation
201: * of display name
202: * @param name the new display name
203: */
204: final protected void internalSetDisplayName(String name) {
205: this .displayName = name;
206: }
207:
208: /**
209: * @return ant name
210: */
211: public String getAntName() {
212: return (String) properties.get(PLAT_PROP_ANT_NAME);
213: }
214:
215: /**
216: * @param antName name of platfrom
217: */
218: public void setAntName(String antName) {
219: if (antName == null || antName.length() == 0) {
220: throw new IllegalArgumentException();
221: }
222: this .properties.put(PLAT_PROP_ANT_NAME, antName);
223: this .firePropertyChange(PROP_ANT_NAME, null, null);
224: }
225:
226: /**
227: * Set platform bootpath to specified values
228: */
229: public void setBootstrapLibraries(List<URL> bs) {
230: assert bs != null;
231: synchronized (this ) {
232: //find differences
233: List<URL> newPath = new ArrayList<URL>();
234: newPath.addAll(bs);
235: ClassPath cp = ClassPathSupport
236: .createClassPath(getAllLibraries());
237: List<ClassPath.Entry> entries = cp.entries();
238: List<FileObject> removed = new ArrayList<FileObject>();
239: for (ClassPath.Entry entry : entries) {
240: URL url = entry.getURL();
241: if (!newPath.remove(url))
242: removed.add(entry.getRoot());
243: }
244:
245: boolean changing = false;
246: bootstrap = new WeakReference<ClassPath>(ClassPathSupport
247: .createClassPath(bs.toArray(new URL[bs.size()])));
248: for (CDCDevice device : devices) {
249: CDCDevice.CDCProfile[] profiles = device.getProfiles();
250: for (CDCDevice.CDCProfile profile : profiles) {
251: String bootp = profile.getBootClassPath();
252:
253: //Remove removed jars
254: List<FileObject> fobs = resolveRelativePathToFileObjects(bootp);
255: for (FileObject fo : removed) {
256: fobs.remove(fo);
257: }
258:
259: //Construct new bootstrap classpath
260: StringBuffer newBS = new StringBuffer();
261: for (URL url : bs) {
262: FileObject fo = URLMapper.findFileObject(url);
263: String name = null;
264: if (fo.isRoot())
265: try {
266: name = fo.getFileSystem()
267: .getDisplayName();
268: } catch (FileStateInvalidException ex) {
269: }
270: else
271: name = fo.getPath();
272:
273: if (newPath.contains(url)) {
274: newBS.append(name);
275: newBS.append(';');
276: }
277:
278: if (fobs.contains(fo)) {
279: newBS.append(name);
280: newBS.append(';');
281: }
282: }
283:
284: changing = true;
285: profile.setBootClassPath(newBS.toString());
286: profile.setRunClassPath(newBS.toString());
287: }
288: }
289: if (changing)
290: firePropertyChange("classpath", null, null);
291: }
292: }
293:
294: /**
295: * @return bootstarap libraries. If there are more platfrom with different classpath supported, return all classpath entries
296: */
297: public ClassPath getBootstrapLibraries() {
298: synchronized (this ) {
299: ClassPath cp = bootstrap == null ? null : bootstrap.get();
300: if (cp != null)
301: return cp;
302: cp = ClassPathSupport.createClassPath(getAllLibraries());
303: bootstrap = new WeakReference<ClassPath>(cp);
304: return cp;
305: }
306: }
307:
308: public ClassPath getBootstrapLibrariesForProfile(
309: String activeDevice, String activeProfile) {
310: if (activeDevice == null || activeProfile == null) { //in such case return all
311: return getBootstrapLibraries();
312: }
313: CDCDevice[] devices = this .getDevices();
314: CDCDevice.CDCProfile active = null;
315: for (int i = 0; devices != null && i < devices.length; i++) {
316: if (devices[i].getName().equals(activeDevice)) {
317: CDCDevice.CDCProfile[] profiles = devices[i]
318: .getProfiles();
319: for (int j = 0; profiles != null && j < profiles.length; j++) {
320: if (profiles[j].getName().equals(activeProfile)) {
321: active = profiles[j];
322: break;
323: }
324: }
325: break;
326: }
327: }
328: if (active != null) {
329: List<FileObject> l = resolveRelativePathToFileObjects(active
330: .getBootClassPath());
331: return ClassPathSupport.createClassPath(l
332: .toArray(new FileObject[l.size()]));
333: }
334: return null;
335: }
336:
337: /**
338: * @return type of platfrom. Note: type must be unique identifier
339: */
340: public String getType() {
341: return type;
342: }
343:
344: /**
345: * @param type of platfrom
346: */
347: public void setType(String type) {
348: this .type = type;
349: }
350:
351: /**
352: * @return maximum class version supported by platform
353: */
354: public String getClassVersion() {
355: return classVersion;
356: }
357:
358: /**
359: * @param classVersion maximum class version for platform
360: */
361: public void setClassVersion(String classVersion) {
362: this .classVersion = classVersion;
363: }
364:
365: public CDCDevice[] getDevices() {
366: return devices;
367: }
368:
369: public void setDevices(CDCDevice[] devices) {
370: this .devices = devices;
371: }
372:
373: /**
374: * This implementation simply reads and parses `java.class.path' property and creates a ClassPath
375: * out of it.
376: * @return ClassPath that represents contents of system property java.class.path.
377: */
378: public ClassPath getStandardLibraries() {
379: synchronized (this ) {
380: ClassPath cp = standardLibs == null ? null : standardLibs
381: .get();
382: if (cp != null)
383: return cp;
384: cp = ClassPathSupport.createClassPath(new ArrayList()); //empty for CDC
385: standardLibs = new WeakReference<ClassPath>(cp);
386: return cp;
387: }
388: }
389:
390: public String getHomePath() {
391: Iterator it = getInstallFolders().iterator();
392: if (it.hasNext()) {
393: FileObject fo = (FileObject) it.next();
394: return FileUtil.toFile(fo).getAbsolutePath();
395: }
396: return null;
397: }
398:
399: /**
400: * Retrieves a collection of {@link org.openide.filesystems.FileObject}s of one or more folders
401: * where the Platform is installed. Typically it returns one folder, but
402: * in some cases there can be more of them.
403: */
404: public final Collection<FileObject> getInstallFolders() {
405: Collection<FileObject> result = new ArrayList<FileObject>();
406: for (URL url : installFolders) {
407: FileObject root = URLMapper.findFileObject(url);
408: if (root != null) {
409: result.add(root);
410: }
411: }
412: return result;
413: }
414:
415: public final FileObject findTool(final String toolName) {
416: //throw new IllegalArgumentException("Not to be used here " + toolName);
417: //return Util.findTool ("",toolName, this.getInstallFolders());
418: System.out.println("findTool: " + toolName);
419: return null;
420: }
421:
422: public final FileObject findTool(final String folder,
423: final String toolName) {
424: return Util
425: .findTool(folder, toolName, this .getInstallFolders());
426: }
427:
428: /**
429: * Returns the location of the source of platform
430: * @return List<URL>
431: */
432: public final ClassPath getSourceFolders() {
433: return this .sources;
434: }
435:
436: public final void setSourceFolders(ClassPath c) {
437: assert c != null;
438: this .sources = c;
439: this .firePropertyChange(PROP_SOURCE_FOLDER, null, null);
440: }
441:
442: /**
443: * Returns the location of the Javadoc for this platform
444: * @return FileObject
445: */
446: public final List<URL> getJavadocFolders() {
447: return this .javadoc;
448: }
449:
450: public final void setJavadocFolders(List<URL> c) {
451: assert c != null;
452: List<URL> safeCopy = Collections
453: .unmodifiableList(new ArrayList<URL>(c));
454: for (URL url : safeCopy) {
455: if (!"jar".equals(url.getProtocol())
456: && FileUtil.isArchiveFile(url)) {
457: throw new IllegalArgumentException(
458: "JavadocFolder must be a folder.");
459: }
460: }
461: this .javadoc = safeCopy;
462: this .firePropertyChange(PROP_JAVADOC_FOLDER, null, null);
463: }
464:
465: public String getVendor() {
466: String s = (String) getSystemProperties().get("java.vm.vendor"); // NOI18N
467: return s == null ? "" : s; // NOI18N
468: }
469:
470: public Specification getSpecification() {
471: if (spec == null) {
472: spec = new Specification(PLATFORM_CDC,
473: new SpecificationVersion(getClassVersion())); //NOI18N
474: }
475: return spec;
476: }
477:
478: public Map getProperties() {
479: return properties;
480: }
481:
482: public Collection getInstallFolderURLs() {
483: return Collections.unmodifiableList(this .installFolders);
484: }
485:
486: private static ClassPath createClassPath(List<URL> urls) {
487: List<PathResourceImplementation> resources = new ArrayList<PathResourceImplementation>();
488: if (urls != null) {
489: for (URL url : urls) {
490: resources.add(ClassPathSupport.createResource(url));
491: }
492: }
493: return ClassPathSupport.createClassPath(resources);
494: }
495:
496: private FileObject[] getAllLibraries() {
497: ArrayList<FileObject> fobs = new ArrayList<FileObject>();
498: for (CDCDevice device : devices) {
499: for (CDCDevice.CDCProfile profile : device.getProfiles()) {
500: List<FileObject> list = resolveRelativePathToFileObjects(profile
501: .getBootClassPath());
502: int lastIndex = -1;
503: for (FileObject fo : list) {
504: if (!fobs.contains(fo))
505: fobs.add(lastIndex + 1, fo);
506: lastIndex = fobs.indexOf(fo);
507: }
508: }
509: }
510: return fobs.toArray(new FileObject[fobs.size()]);
511: }
512:
513: private List<FileObject> resolveRelativePathToFileObjects(
514: String path) {
515: ArrayList<FileObject> res = new ArrayList<FileObject>();
516: if (path == null)
517: return res;
518: String paths[] = PropertyUtils.tokenizePath(path);
519: for (String pth : paths) {
520: FileObject fo = resolveRelativePathToFileObject(pth.trim());
521: if (fo != null)
522: res.add(fo);
523: }
524: return res;
525: }
526:
527: public FileObject resolveRelativePathToFileObject(String path) {
528: if (path == null || path.length() <= 0)
529: return null;
530: File f;
531: if (path.startsWith(PLATFORM_STRING_PREFIX)) {
532: FileObject fo = URLMapper.findFileObject(installFolders
533: .iterator().next());
534: f = new File(FileUtil.toFile(fo), path
535: .substring(PLATFORM_STRING_PREFIX.length()));
536: } else {
537: f = new File(path);
538: }
539: f = FileUtil.normalizeFile(f);
540: FileObject fo = FileUtil.toFileObject(f);
541: if (fo == null || !FileUtil.isArchiveFile(fo))
542: return fo;
543: return FileUtil.getArchiveRoot(fo);
544: }
545:
546: public boolean isFatJar() {
547: return fatJar;
548: }
549: }
|