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.projectimport.eclipse;
043:
044: import java.io.BufferedInputStream;
045: import java.io.FileInputStream;
046: import java.io.IOException;
047: import java.io.InputStream;
048: import org.netbeans.modules.projectimport.ProjectImporterException;
049: import org.openide.ErrorManager;
050: import org.openide.xml.XMLUtil;
051: import org.xml.sax.Attributes;
052: import org.xml.sax.InputSource;
053: import org.xml.sax.SAXException;
054: import org.xml.sax.SAXParseException;
055: import org.xml.sax.XMLReader;
056: import org.xml.sax.helpers.DefaultHandler;
057:
058: /**
059: * Parses given project's .project file and fills up the project with found
060: * data.
061: *
062: * @author mkrauskopf
063: */
064: final class ProjectParser extends DefaultHandler {
065:
066: private final EclipseProject project;
067: private ClassPath.Link currentLink;
068:
069: private static final String JAVA_NATURE = "org.eclipse.jdt.core.javanature"; // NOI18N
070:
071: // elements names
072: private static final String PROJECT_DESCRIPTION = "projectDescription"; // NOI18N
073: private static final String LINKED_RESOURCES = "linkedResources"; // NOI18N
074: private static final String LINK = "link"; // NOI18N
075: private static final String NAME = "name"; // NOI18N
076: private static final String TYPE = "type"; // NOI18N
077: private static final String LOCATION = "location"; // NOI18N
078: private static final String NATURES = "natures"; // NOI18N
079: private static final String NATURE = "nature"; // NOI18N
080:
081: // indicates current position in a xml document
082: private static final int POSITION_NONE = 0;
083: private static final int POSITION_PROJECT_DESCRIPTION = 1;
084: private static final int POSITION_PROJECT_NAME = 2;
085: private static final int POSITION_LINKED_RESOURCES = 3;
086: private static final int POSITION_LINK = 4;
087: private static final int POSITION_LINK_NAME = 5;
088: private static final int POSITION_LINK_TYPE = 6;
089: private static final int POSITION_LINK_LOCATION = 7;
090: private static final int POSITION_NATURES = 8;
091: private static final int POSITION_NATURE = 9;
092: private static final int POSITION_UNUSED = 1000;
093:
094: private int position = POSITION_NONE;
095: private int unusedInner = 0;
096: private StringBuffer chars;
097:
098: /** Creates a new instance of ProjectParser */
099: private ProjectParser(EclipseProject project) {
100: this .project = project;
101: }
102:
103: static void parse(EclipseProject project)
104: throws ProjectImporterException {
105: ProjectParser parser = new ProjectParser(project);
106: parser.load();
107: }
108:
109: /** Parses a given InputSource and fills up a EclipseProject */
110: private void load() throws ProjectImporterException {
111: InputStream projectIS = null;
112: try {
113: projectIS = new BufferedInputStream(new FileInputStream(
114: project.getProjectFile()));
115: XMLReader reader = XMLUtil.createXMLReader(false, true);
116: reader.setContentHandler(this );
117: reader.setErrorHandler(this );
118: chars = new StringBuffer(); // initialization
119: reader.parse(new InputSource(projectIS)); // start parsing
120: } catch (IOException e) {
121: throw new ProjectImporterException(e);
122: } catch (SAXException e) {
123: throw new ProjectImporterException(e);
124: } finally {
125: if (projectIS != null) {
126: try {
127: projectIS.close();
128: } catch (IOException e) {
129: ErrorManager.getDefault().log(ErrorManager.WARNING,
130: "Unable to close projectInputStream: " + e); // NOI18N
131: }
132: }
133: }
134: }
135:
136: public void characters(char ch[], int offset, int length)
137: throws SAXException {
138: chars.append(ch, offset, length);
139: }
140:
141: public void startElement(String uri, String localName,
142: String qName, Attributes attributes) throws SAXException {
143:
144: chars.setLength(0);
145: switch (position) {
146: case POSITION_NONE:
147: if (localName.equals(PROJECT_DESCRIPTION)) {
148: position = POSITION_PROJECT_DESCRIPTION;
149: } else {
150: throw (new SAXException("First element has to be " // NOI18N
151: + PROJECT_DESCRIPTION + ", but is " + localName)); // NOI18N
152: }
153: break;
154: case POSITION_PROJECT_DESCRIPTION:
155: if (localName.equals(NAME)) {
156: position = POSITION_PROJECT_NAME;
157: } else if (localName.equals(LINKED_RESOURCES)) {
158: position = POSITION_LINKED_RESOURCES;
159: } else if (localName.equals(NATURES)) {
160: position = POSITION_NATURES;
161: } else {
162: position = POSITION_UNUSED;
163: unusedInner++;
164: }
165: break;
166: case POSITION_NATURES:
167: if (localName.equals(NATURE)) {
168: position = POSITION_NATURE;
169: }
170: break;
171: case POSITION_LINKED_RESOURCES:
172: if (localName.equals(LINK)) {
173: currentLink = new ClassPath.Link();
174: position = POSITION_LINK;
175: }
176: break;
177: case POSITION_LINK:
178: if (localName.equals(NAME)) {
179: position = POSITION_LINK_NAME;
180: } else if (localName.equals(TYPE)) {
181: position = POSITION_LINK_TYPE;
182: } else if (localName.equals(LOCATION)) {
183: position = POSITION_LINK_LOCATION;
184: }
185: break;
186: default:
187: position = POSITION_UNUSED;
188: unusedInner++;
189: }
190: }
191:
192: public void endElement(String uri, String localName, String qName)
193: throws SAXException {
194: switch (position) {
195: case POSITION_PROJECT_DESCRIPTION:
196: // parsing ends
197: position = POSITION_NONE;
198: break;
199: case POSITION_PROJECT_NAME:
200: if (unusedInner == 0) {
201: if (localName.equals(NAME)) {
202: // Project names cannot have leading/trailing whitespace
203: // as they are IResource names.
204: project.setName(chars.toString().trim());
205: position = POSITION_PROJECT_DESCRIPTION;
206: }
207: break;
208: }
209: case POSITION_LINKED_RESOURCES:
210: case POSITION_NATURES:
211: position = POSITION_PROJECT_DESCRIPTION;
212: break;
213: case POSITION_NATURE:
214: if (localName.equals(NATURE)) {
215: String nature = chars.toString().trim();
216: if (JAVA_NATURE.equals(nature)) {
217: project.setJavaNature(true);
218: } else {
219: project.addOtherNature(nature);
220: }
221: }
222: position = POSITION_NATURES;
223: break;
224: case POSITION_LINK:
225: processLink(localName);
226: break;
227: case POSITION_LINK_NAME:
228: processLinkName(localName);
229: break;
230: case POSITION_LINK_TYPE:
231: processLinkType(localName);
232: break;
233: case POSITION_LINK_LOCATION:
234: processLinkLocation(localName);
235: break;
236: case POSITION_UNUSED:
237: if (--unusedInner == 0) {
238: position = POSITION_PROJECT_DESCRIPTION;
239: }
240: break;
241: default:
242: ErrorManager.getDefault().log(ErrorManager.WARNING,
243: "Unknown state reached in ProjectParser, " + // NOI18N
244: "position: " + position); // NOI18N
245: }
246: chars.setLength(0);
247: }
248:
249: public void warning(SAXParseException e) throws SAXException {
250: ErrorManager.getDefault().log(ErrorManager.WARNING,
251: "Warning occurred: " + e);
252: }
253:
254: public void error(SAXParseException e) throws SAXException {
255: ErrorManager.getDefault().log(ErrorManager.WARNING,
256: "Error occurres: " + e);
257: throw e;
258: }
259:
260: public void fatalError(SAXParseException e) throws SAXException {
261: ErrorManager.getDefault().log(ErrorManager.WARNING,
262: "Fatal error occurres: " + e);
263: throw e;
264: }
265:
266: /**
267: * If a link is OK appends it to an <code>EclipseProject</code> links.
268: */
269: private void processLink(String elementName) throws SAXException {
270: if (elementName.equals(LINK)) {
271: position = POSITION_LINKED_RESOURCES;
272: // Make sure that you have something reasonable
273: String name = currentLink.getName();
274: int type = currentLink.getType();
275: String location = currentLink.getLocation();
276: try {
277: if ((name == null) || name.length() == 0) {
278: throw new SAXException(
279: "Link's name cannot be empty"); //NOI18N
280: }
281: if (type == ClassPath.Link.TYPE_INVALID) {
282: throw new SAXException(
283: "Link's type cannot be equal to " + type); //NOI18N
284: }
285: if ((location == null) || location.length() == 0) {
286: throw new SAXException(
287: "Link's location cannot be empty"); //NOI18N
288: }
289: project.addLink(currentLink);
290: } finally {
291: currentLink = null;
292: }
293: }
294: }
295:
296: /** Sets location for currently processed link. */
297: private void processLinkLocation(String elementName)
298: throws SAXException {
299: if (elementName.equals(LOCATION)) {
300: String location = chars.toString().trim();
301: if (currentLink.getLocation() != null) {
302: throw new SAXException(
303: "Link's location was already set. There can be only "
304: + //NOI18N
305: "one location element inside of link element"); //NOI18N
306: }
307: currentLink.setLocation(location);
308: position = POSITION_LINK;
309: }
310: }
311:
312: /** Sets name for currently processed link. */
313: private void processLinkName(String elementName)
314: throws SAXException {
315: if (elementName.equals(NAME)) {
316: String name = chars.toString().trim();
317: if (currentLink.getName() != null) {
318: throw new SAXException(
319: "Link's name was already set. There can be only "
320: + //NOI18N
321: "one name element inside of link element"); //NOI18N
322: }
323: currentLink.setName(name);
324: position = POSITION_LINK;
325: }
326: }
327:
328: /** Sets type for currently processed link. */
329: private void processLinkType(String elementName)
330: throws SAXException {
331: if (elementName.equals(TYPE)) {
332: // make sure that type wasn't set yet
333: if (currentLink.getType() != ClassPath.Link.TYPE_INVALID) {
334: throw new SAXException(
335: "Link's type was already set. There can be only "
336: + //NOI18N
337: "one type element inside of link element"); //NOI18N
338: }
339: try {
340: currentLink.setType(Integer.parseInt(chars.toString()
341: .trim()));
342: position = POSITION_LINK;
343: } catch (NumberFormatException e) {
344: throw new SAXException("Link's type has to be a " + //NOI18N
345: "number but is: " + chars.toString().trim()); //NOI18N
346: }
347: }
348: }
349:
350: }
|