001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.cli.common.modules;
018
019 import com.intellij.openapi.util.io.StreamUtil;
020 import com.intellij.util.SmartList;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.jet.cli.common.messages.*;
023 import org.xml.sax.Attributes;
024 import org.xml.sax.SAXException;
025 import org.xml.sax.helpers.DefaultHandler;
026
027 import javax.xml.parsers.ParserConfigurationException;
028 import javax.xml.parsers.SAXParser;
029 import javax.xml.parsers.SAXParserFactory;
030 import java.io.*;
031 import java.util.Collections;
032 import java.util.List;
033
034 import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.*;
035 import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.*;
036
037 public class ModuleXmlParser {
038
039 public static final String MODULES = "modules";
040 public static final String MODULE = "module";
041 public static final String NAME = "name";
042 public static final String OUTPUT_DIR = "outputDir";
043 public static final String SOURCES = "sources";
044 public static final String PATH = "path";
045 public static final String CLASSPATH = "classpath";
046 public static final String EXTERNAL_ANNOTATIONS = "externalAnnotations";
047
048 @NotNull
049 public static List<ModuleDescription> parse(@NotNull String xmlFile, @NotNull MessageCollector messageCollector) {
050 FileInputStream stream = null;
051 try {
052 stream = new FileInputStream(xmlFile);
053 //noinspection IOResourceOpenedButNotSafelyClosed
054 return new ModuleXmlParser(messageCollector).parse(new BufferedInputStream(stream));
055 }
056 catch (FileNotFoundException e) {
057 MessageCollectorUtil.reportException(messageCollector, e);
058 return Collections.emptyList();
059 }
060 finally {
061 StreamUtil.closeStream(stream);
062 }
063 }
064
065 private final MessageCollector messageCollector;
066 private final List<ModuleDescription> result = new SmartList<ModuleDescription>();
067 private DefaultHandler currentState;
068
069 private ModuleXmlParser(@NotNull MessageCollector messageCollector) {
070 this.messageCollector = messageCollector;
071 }
072
073 private void setCurrentState(@NotNull DefaultHandler currentState) {
074 this.currentState = currentState;
075 }
076
077 private List<ModuleDescription> parse(@NotNull InputStream xml) {
078 try {
079 setCurrentState(initial);
080 SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
081 saxParser.parse(xml, new DelegatedSaxHandler() {
082 @NotNull
083 @Override
084 protected DefaultHandler getDelegate() {
085 return currentState;
086 }
087 });
088 return result;
089 }
090 catch (ParserConfigurationException e) {
091 MessageCollectorUtil.reportException(messageCollector, e);
092 }
093 catch (SAXException e) {
094 messageCollector.report(ERROR, MessageRenderer.PLAIN.renderException(e), NO_LOCATION);
095 }
096 catch (IOException e) {
097 MessageCollectorUtil.reportException(messageCollector, e);
098 }
099 return Collections.emptyList();
100 }
101
102 private final DefaultHandler initial = new DefaultHandler() {
103 @Override
104 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
105 if (!MODULES.equalsIgnoreCase(qName)) {
106 throw createError(qName);
107 }
108
109 setCurrentState(insideModules);
110 }
111 };
112
113 private final DefaultHandler insideModules = new DefaultHandler() {
114 @Override
115 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
116 if (!MODULE.equalsIgnoreCase(qName)) {
117 throw createError(qName);
118 }
119
120 setCurrentState(new InsideModule(getAttribute(attributes, NAME, qName), getAttribute(attributes, OUTPUT_DIR, qName)));
121 }
122
123 @Override
124 public void endElement(String uri, String localName, String qName) throws SAXException {
125 if (MODULE.equalsIgnoreCase(qName) || MODULES.equalsIgnoreCase(qName)) {
126 setCurrentState(insideModules);
127 }
128 }
129 };
130
131 private class InsideModule extends DefaultHandler {
132
133 private final ModuleDescription.Impl moduleDescription;
134 private InsideModule(String name, String outputDir) {
135 this.moduleDescription = new ModuleDescription.Impl();
136 this.moduleDescription.setName(name);
137 this.moduleDescription.setOutputDir(outputDir);
138 result.add(moduleDescription);
139 }
140
141 @Override
142 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
143 if (SOURCES.equalsIgnoreCase(qName)) {
144 String path = getAttribute(attributes, PATH, qName);
145 moduleDescription.addSourcePath(path);
146 }
147 else if (CLASSPATH.equalsIgnoreCase(qName)) {
148 String path = getAttribute(attributes, PATH, qName);
149 moduleDescription.addClassPath(path);
150 }
151 else if (EXTERNAL_ANNOTATIONS.equalsIgnoreCase(qName)) {
152 String path = getAttribute(attributes, PATH, qName);
153 moduleDescription.addAnnotationPath(path);
154 }
155 else {
156 throw createError(qName);
157 }
158 }
159
160 @Override
161 public void endElement(String uri, String localName, String qName) throws SAXException {
162 if (MODULE.equalsIgnoreCase(qName)) {
163 setCurrentState(insideModules);
164 }
165 }
166 }
167
168 @NotNull
169 private static String getAttribute(Attributes attributes, String qName, String tag) throws SAXException {
170 String name = attributes.getValue(qName);
171 if (name == null) {
172 throw new SAXException("No '" + qName + "' attribute for " + tag);
173 }
174 return name;
175 }
176
177 private static SAXException createError(String qName) throws SAXException {
178 return new SAXException("Unexpected tag: " + qName);
179 }
180 }