/**
* JBoss, Home of Professional Open Source
* Copyright ${year}, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.arquillian.rusheye.parser;
import com.ctc.wstx.exc.WstxParsingException;
import com.ctc.wstx.exc.WstxValidationException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.StreamFilter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.commons.io.FileUtils;
import org.codehaus.stax2.XMLInputFactory2;
import org.codehaus.stax2.XMLStreamReader2;
import org.codehaus.stax2.ri.Stax2FilteredStreamReader;
import org.codehaus.stax2.validation.XMLValidationSchema;
import org.codehaus.stax2.validation.XMLValidationSchemaFactory;
import org.arquillian.rusheye.exception.ConfigurationException;
import org.arquillian.rusheye.exception.ConfigurationValidationException;
import org.arquillian.rusheye.exception.ParsingException;
import org.arquillian.rusheye.listener.SuiteListener;
import org.arquillian.rusheye.listener.SuiteListenerAdapter;
import org.arquillian.rusheye.suite.GlobalConfiguration;
import org.arquillian.rusheye.suite.Mask;
import org.arquillian.rusheye.suite.Pattern;
import org.arquillian.rusheye.suite.Properties;
import org.arquillian.rusheye.suite.Test;
import org.arquillian.rusheye.suite.VisualSuite;
/**
* @author <a href="mailto:lfryc@redhat.com">Lukas Fryc</a>
* @version $Revision$
*/
public final class Parser {
private Set<SuiteListener> listeners = new LinkedHashSet<SuiteListener>();
private Handler handler = new Handler(listeners);
private Properties properties;
public Parser() {
this.registerListener(new ParserListenerRegistrationListener());
}
public void parseResource(String resourceName) {
InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(resourceName);
parseStream(inputStream);
}
public void parseStream(InputStream inputStream) {
try {
File tmp = File.createTempFile(Parser.class.getName(), ".tmp");
BufferedInputStream in = new BufferedInputStream(inputStream);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(tmp));
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
in.close();
parseFileTempFile(tmp);
} catch (IOException e) {
throw new ParsingException(e);
}
}
public void parseFile(File file) {
parseFile(file, false);
}
public void parseFileTempFile(File file) {
parseFile(file, true);
}
private void parseFile(File file, boolean tmpfile) {
VisualSuite visualSuite = null;
try {
XMLValidationSchemaFactory schemaFactory = XMLValidationSchemaFactory
.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
URL schemaURL = getClass().getClassLoader().getResource("org/arquillian/rusheye/visual-suite.xsd");
XMLValidationSchema schema = schemaFactory.createSchema(schemaURL);
XMLInputFactory2 factory = (XMLInputFactory2) XMLInputFactory.newInstance();
StreamFilter filter = new StreamFilter() {
@Override
public boolean accept(XMLStreamReader reader) {
return reader.isStartElement();
}
};
XMLStreamReader2 reader = factory.createXMLStreamReader(file);
XMLStreamReader2 filteredReader = new Stax2FilteredStreamReader(reader, filter);
reader.validateAgainst(schema);
// EventFilter filter = new EventFilter() {
// @Override
// public boolean accept(XMLEvent reader) {
// return reader.isStartElement();
// }
// };
//
// XMLEventReader reader = factory.createXMLEventReader(file);
// XMLEventReader filteredReader = factory.createFilteredReader(reader, filter);
JAXBContext ctx = JAXBContext.newInstance(VisualSuite.class.getPackage().getName());
Unmarshaller um = ctx.createUnmarshaller();
UnmarshallerMultiListener listener = new UnmarshallerMultiListener();
um.setListener(listener);
// skip parsing of the first element - visual-suite
filteredReader.nextTag();
visualSuite = new VisualSuite();
handler.setVisualSuite(visualSuite);
handler.getContext().invokeListeners().onSuiteStarted(visualSuite);
listener.registerListener(new UniqueIdentityChecker(handler.getContext()));
while (filteredReader.hasNext()) {
try {
// go on the start of the next tag
filteredReader.nextTag();
Object o = um.unmarshal(reader);
if (o instanceof GlobalConfiguration) {
GlobalConfiguration globalConfiguration = (GlobalConfiguration) o;
handler.getContext().setCurrentConfiguration(globalConfiguration);
visualSuite.setGlobalConfiguration(globalConfiguration);
handler.getContext().invokeListeners().onConfigurationReady(visualSuite);
RetriverInjector retriverInjector = new RetriverInjector(this);
for (Mask mask : globalConfiguration.getMasks()) {
retriverInjector.afterUnmarshal(mask, null);
}
listener.registerListener(retriverInjector);
}
if (o instanceof Test) {
Test test = (Test) o;
handler.getContext().setCurrentConfiguration(test);
handler.getContext().setCurrentTest(test);
for (Pattern pattern : test.getPatterns()) {
handler.getContext().invokeListeners().onPatternReady(test, pattern);
}
Test testWrapped = ConfigurationCompiler.wrap(test, visualSuite.getGlobalConfiguration());
handler.getContext().invokeListeners().onTestReady(testWrapped);
}
} catch (WstxParsingException e) {
// intentionally blank - wrong end of document detection
}
}
} catch (XMLStreamException e) {
throw handleParsingException(e, e);
} catch (JAXBException e) {
throw handleParsingException(e, e.getLinkedException());
} finally {
if (visualSuite != null && handler.getContext() != null) {
handler.getContext().invokeListeners().onSuiteReady(visualSuite);
}
if (tmpfile) {
FileUtils.deleteQuietly(file);
}
}
}
private RuntimeException handleParsingException(Throwable originalException, Throwable cause) {
if (cause != null && cause instanceof WstxValidationException) {
String message = cause.getMessage().replaceAll("\n", "");
return new ConfigurationValidationException(message, cause);
}
return new ParsingException(originalException);
}
public void registerListener(SuiteListener parserListener) {
synchronized (parserListener) {
if (listeners.contains(parserListener)) {
return;
}
listeners.add(parserListener);
}
}
public void unregisterListener(SuiteListener parserListener) {
synchronized (listeners) {
if (listeners.contains(parserListener)) {
listeners.remove(parserListener);
}
}
throw new IllegalStateException("Given parser isn't registered");
}
Handler getHandler() {
return handler;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
private class ParserListenerRegistrationListener extends SuiteListenerAdapter {
@Override
public void onConfigurationReady(VisualSuite visualSuite) {
for (SuiteListener listener : visualSuite.getGlobalConfiguration().getListeners()) {
if (Parser.this.properties != null) {
listener.setProperties(Parser.this.properties);
}
listener.onSuiteStarted(visualSuite);
listener.onConfigurationReady(visualSuite);
Parser.this.registerListener(listener);
}
if (listeners.size() == 1) {
throw new ConfigurationException("No ParserListener was registered to process parsed tests");
}
}
}
}