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.apisupport.project.metainf;
043:
044: import java.io.BufferedReader;
045: import java.io.File;
046: import java.io.IOException;
047: import java.io.InputStream;
048: import java.io.InputStreamReader;
049: import java.io.OutputStream;
050: import java.io.OutputStreamWriter;
051: import java.io.PrintWriter;
052: import java.util.ArrayList;
053: import java.util.Enumeration;
054: import java.util.Iterator;
055: import java.util.List;
056: import java.util.Set;
057: import java.util.jar.Attributes;
058: import java.util.jar.JarEntry;
059: import java.util.jar.JarFile;
060: import org.netbeans.api.project.Project;
061: import org.netbeans.api.project.ProjectManager;
062: import org.netbeans.api.queries.VisibilityQuery;
063: import org.netbeans.modules.apisupport.project.NbModuleProject;
064: import org.netbeans.modules.apisupport.project.spi.NbModuleProvider;
065: import org.netbeans.modules.apisupport.project.SuiteProvider;
066: import org.netbeans.modules.apisupport.project.Util;
067: import org.netbeans.modules.apisupport.project.layers.LayerUtils;
068: import org.netbeans.modules.apisupport.project.suite.SuiteProject;
069: import org.openide.ErrorManager;
070: import org.openide.filesystems.FileObject;
071: import org.openide.filesystems.FileUtil;
072:
073: /**
074: * Representation of a record in META-INF/services.
075: *
076: * @author pzajac
077: */
078: final class Service {
079:
080: private final String codebase;
081: private final String fileName;
082: private final List<String> classes;
083:
084: static final String META_INF_SERVICES = "META-INF/services";
085:
086: /** Creates a new instance of Service */
087: public Service(String codebase, String fileName,
088: List<String> classes) {
089: this .codebase = codebase;
090: this .fileName = fileName;
091: this .classes = classes;
092: }
093:
094: static Service createService(String codebase, String fileName,
095: InputStream jarIs) throws IOException {
096: List<String> list = new ArrayList<String>();
097: BufferedReader reader = new BufferedReader(
098: new InputStreamReader(jarIs, "UTF-8"));
099: String line = null;
100: while ((line = reader.readLine()) != null) {
101: line = line.trim();
102: if (!line.startsWith("#") && line.length() != 0) {
103: list.add(line);
104: }
105: }
106: return new Service(codebase, fileName, list);
107: }
108:
109: static List<Service> readServices(File jarFile) {
110: List<Service> services = new ArrayList<Service>();
111: try {
112: JarFile jar = new JarFile(jarFile);
113: try {
114: Attributes attrs = jar.getManifest()
115: .getMainAttributes();
116: String codebase = attrs.getValue("OpenIDE-Module"); // NOI18N
117: Enumeration /*JarEntry*/entries = jar.entries();
118: while (entries.hasMoreElements()) {
119: JarEntry entry = (JarEntry) entries.nextElement();
120: if (entry.getName().startsWith(META_INF_SERVICES)) {
121: String name = entry.getName().substring(
122: META_INF_SERVICES.length() + 1).trim();
123: if (!name.equals("")) { // NOI18N
124: InputStream is = jar.getInputStream(entry);
125: try {
126: services.add(createService(codebase,
127: name.intern(), is));
128: } finally {
129: is.close();
130: }
131: }
132: }
133: }
134: } finally {
135: jar.close();
136: }
137: } catch (IOException ioe) {
138: ErrorManager.getDefault().notify(ErrorManager.ERROR, ioe);
139: }
140: return services;
141: }
142:
143: static List<Service> getOnlyProjectServices(Project project) {
144: List<Service> services = new ArrayList<Service>();
145: try {
146: NbModuleProvider info = project.getLookup().lookup(
147: NbModuleProvider.class);
148: FileObject mIServicesFolder = null;
149: mIServicesFolder = SUtil.getServicesFolder(project, false);
150: // get META-INF.services folder
151: if (mIServicesFolder != null) {
152: String codebase = info.getCodeNameBase();
153: FileObject servicesFOs[] = mIServicesFolder
154: .getChildren();
155: for (int foIt = 0; foIt < servicesFOs.length; foIt++) {
156: if (servicesFOs[foIt].isData()
157: && VisibilityQuery.getDefault().isVisible(
158: servicesFOs[foIt])) {
159: InputStream is = servicesFOs[foIt]
160: .getInputStream();
161: try {
162: services
163: .add(createService(codebase,
164: servicesFOs[foIt]
165: .getNameExt(), is));
166: } finally {
167: is.close();
168: }
169: }
170: }
171: }
172: } catch (IOException ioe) {
173: ErrorManager.getDefault().notify(ErrorManager.ERROR, ioe);
174: }
175: return services;
176: }
177:
178: public String getCodebase() {
179: return codebase;
180: }
181:
182: public String getFileName() {
183: return fileName;
184: }
185:
186: public List<String> getClasses() {
187: return classes;
188: }
189:
190: public boolean containsClass(String name) {
191: return classes.indexOf(name) != -1;
192: }
193:
194: public void removeClass(String name) {
195: classes.remove(name);
196: }
197:
198: private static Set<File> getJars(Project p) throws IOException {
199: if (p == null) {
200: // testing
201: return SUtil.getPlatformJars();
202: } else {
203: NbModuleProvider.NbModuleType type = (p.getLookup()
204: .lookup(org.netbeans.modules.apisupport.project.spi.NbModuleProvider.class))
205: .getModuleType();
206: if (type == NbModuleProvider.STANDALONE) {
207: return LayerUtils
208: .getPlatformJarsForStandaloneProject(p);
209: } else if (type == NbModuleProvider.SUITE_COMPONENT) {
210: SuiteProvider suiteProv = p
211: .getLookup()
212: .lookup(
213: org.netbeans.modules.apisupport.project.SuiteProvider.class);
214: assert suiteProv != null : p;
215: File suiteDir = suiteProv.getSuiteDirectory();
216: if (suiteDir == null || !suiteDir.isDirectory()) {
217: throw new IOException("Could not locate suite for "
218: + p); // NOI18N
219: }
220: Project suite = ProjectManager.getDefault()
221: .findProject(FileUtil.toFileObject(suiteDir));
222: if (!(suite instanceof SuiteProject)) {
223: throw new IOException("Could not load suite for "
224: + p + " from " + suiteDir); // NOI18N
225: }
226: return LayerUtils
227: .getPlatformJarsForSuiteComponentProject(p,
228: (SuiteProject) suite);
229: } else if (type == NbModuleProvider.NETBEANS_ORG) {
230: /// Is it really correct?
231: // [TODO]
232: return LayerUtils
233: .getPlatformJarsForStandaloneProject(p);
234: } else {
235: throw new AssertionError(type);
236: }
237: }
238: }
239:
240: static List<Service> getPlatfromServices(Project p)
241: throws IOException {
242: NbModuleProvider.NbModuleType type = Util.getModuleType(p);
243: List<Service> services = new ArrayList<Service>();
244: if (type == NbModuleProvider.NETBEANS_ORG) {
245: // special case fro nborg modules
246: Set<NbModuleProject> projects = LayerUtils
247: .getProjectsForNetBeansOrgProject((NbModuleProject) p);
248: Iterator it = projects.iterator();
249: while (it.hasNext()) {
250: services
251: .addAll(getOnlyProjectServices((NbModuleProject) it
252: .next()));
253: }
254: } else {
255: Set<File> jars = getJars(p);
256: for (File jarFile : jars) {
257: services.addAll(readServices(jarFile));
258: }
259: }
260: return services;
261: }
262:
263: void removeClass(String className, Project project) {
264: String removedClass = "-" + className;
265: removedClass = removedClass.intern();
266: if (containsClass(className)) {
267: removeClass(className);
268: } else if (containsClass(removedClass)) {
269: removeClass(removedClass);
270: } else {
271: classes.add(removedClass);
272: }
273: write(project);
274: }
275:
276: void write(Project project) {
277: try {
278: FileObject mIServicesFolder = null;
279: mIServicesFolder = SUtil.getServicesFolder(project, true);
280: FileObject serviceFo = mIServicesFolder
281: .getFileObject(getFileName());
282: if (classes.size() > 0) {
283: if (serviceFo == null) {
284: serviceFo = mIServicesFolder
285: .createData(getFileName());
286: }
287: OutputStream os = serviceFo.getOutputStream();
288: try {
289: PrintWriter w = new PrintWriter(
290: new OutputStreamWriter(os, "UTF-8"));
291: for (String clazz : classes) {
292: w.println(clazz);
293: }
294: } finally {
295: os.close();
296: }
297: } else {
298: // no service, remove file
299: serviceFo.delete();
300: }
301: } catch (IOException ioe) {
302: ErrorManager.getDefault().notify(ioe);
303: }
304: }
305:
306: }
|