/*
* Copyright 2011 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.semantics.lang.dl;
import com.clarkparsia.empire.Empire;
import com.clarkparsia.empire.EmpireOptions;
import com.clarkparsia.empire.config.ConfigKeys;
import com.clarkparsia.empire.config.EmpireConfiguration;
import com.clarkparsia.empire.sesame.OpenRdfEmpireModule;
import com.clarkparsia.empire.sesame.RepositoryDataSourceFactory;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import org.apache.commons.lang.StringUtils;
import org.drools.io.ResourceFactory;
import org.drools.semantics.UIdAble;
import org.drools.semantics.builder.DLFactory;
import org.drools.semantics.builder.DLFactoryBuilder;
import org.drools.semantics.builder.DLFactoryConfiguration;
import org.drools.semantics.builder.model.OntoModel;
import org.drools.shapes.OntoModelCompiler;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import thewebsemantic.binding.Jenabean;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.spi.PersistenceProvider;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertFalse;
/**
* This is a sample class to launch a rule.
*/
@SuppressWarnings("restriction")
public class DL_9_CompilationTest {
protected DLFactory factory = DLFactoryBuilder.newDLFactoryInstance();
@Rule
public TemporaryFolder folder = new TemporaryFolder();
protected OntoModelCompiler compiler;
@Test
public void testDiamondOptimizedHierarchyCompilation() {
OntoModel results = factory.buildModel( "diamond",
ResourceFactory.newClassPathResource( "ontologies/diamondProp2.manchester.owl" ),
DLFactoryConfiguration.newConfiguration( OntoModel.Mode.OPTIMIZED ) );
assertTrue( results.isHierarchyConsistent() );
compiler = new OntoModelCompiler( results, folder.getRoot() );
// ****** Stream the java interfaces
boolean javaOut = compiler.streamJavaInterfaces( true );
assertTrue( javaOut );
// ****** Stream the XSDs, the JaxB customizations abd the persistence configuration
boolean xsdOut = compiler.streamXSDsWithBindings( true );
assertTrue( xsdOut );
File f = new File( compiler.getMetaInfDir() + File.separator + results.getDefaultPackage() + ".xsd" );
try {
Document dox = parseXML( f, true );
NodeList types = dox.getElementsByTagName( "xsd:complexType" );
assertEquals( 10, types.getLength() );
NodeList elements = dox.getElementsByTagName( "xsd:element" );
assertEquals( 12 + 14, elements.getLength() );
} catch ( Exception e ) {
fail( e.getMessage() );
}
showDirContent( folder );
File b = new File( compiler.getMetaInfDir() + File.separator + results.getDefaultPackage() + ".xjb" );
try {
Document dox = parseXML( b, false );
NodeList types = dox.getElementsByTagName( "bindings" );
assertEquals( 28, types.getLength() );
} catch ( Exception e ) {
fail( e.getMessage() );
}
showDirContent( folder );
// ****** Generate sources
boolean mojo = compiler.mojo( Arrays.asList(
"-extension",
"-Xjaxbindex",
"-Xannotate",
"-Xinheritance",
"-XtoString",
"-Xcopyable",
"-Xmergeable",
"-Xvalue-constructor",
"-Xfluent-api",
"-Xkey-equality",
"-Xsem-accessors",
"-Xdefault-constructor",
"-Xmetadata",
"-Xinject-code"),
OntoModelCompiler.MOJO_VARIANTS.JPA2 );
assertTrue( mojo );
File klass = new File( compiler.getXjcDir().getPath()
+ File.separator
+ results.getDefaultPackage().replace(".", File.separator)
+ File.separator
+ "BottomImpl.java" );
printSourceFile( klass, System.out );
showDirContent( folder );
// ****** Do compile sources
List<Diagnostic<? extends JavaFileObject>> diagnostics = compiler.doCompile();
boolean success = true;
for ( Diagnostic diag : diagnostics ) {
System.out.println( "ERROR : " + diag );
if ( diag.getKind() == Diagnostic.Kind.ERROR ) {
success = false;
}
}
assertTrue( success );
showDirContent( folder );
try {
parseXML( new File( compiler.getBinDir() + "/META-INF/" + "persistence.xml" ), true );
} catch ( Exception e ) {
e.printStackTrace();
}
try {
ClassLoader urlKL = new URLClassLoader(
new URL[] { compiler.getBinDir().toURI().toURL() },
Thread.currentThread().getContextClassLoader()
);
testPersistenceWithInstance( urlKL, "org.jboss.drools.semantics.diamond2.Bottom", results.getName() );
} catch ( Exception e ) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
fail( e.getMessage() );
}
}
@Test
public void testIncrementalCompilation() {
try {
OntoModel diamond = factory.buildModel( "diamondX",
ResourceFactory.newClassPathResource( "ontologies/diamondProp.manchester.owl" ),
DLFactoryConfiguration.newConfiguration( OntoModel.Mode.OPTIMIZED ) );
compiler = new OntoModelCompiler( diamond, folder.getRoot() );
List<Diagnostic<? extends JavaFileObject>> diag1 = compiler.compileOnTheFly( OntoModelCompiler.minimalOptions, OntoModelCompiler.MOJO_VARIANTS.JPA2 );
for ( Diagnostic<?> dx : diag1 ) {
System.out.println( dx );
assertFalse( dx.getKind() == Diagnostic.Kind.ERROR );
}
showDirContent( folder );
ClassLoader urlKL = new URLClassLoader(
new URL[] { compiler.getBinDir().toURI().toURL() },
Thread.currentThread().getContextClassLoader()
);
OntoModel results = factory.buildModel( "diamondInc",
ResourceFactory.newClassPathResource( "ontologies/dependency.test.owl" ),
DLFactoryConfiguration.newConfiguration( OntoModel.Mode.OPTIMIZED ),
urlKL );
System.out.println( results );
Class bot = Class.forName( "org.jboss.drools.semantics.diamond.BottomImpl", true, urlKL );
Class botIF = Class.forName( "org.jboss.drools.semantics.diamond.Bottom", true, urlKL );
Assert.assertNotNull( bot );
Assert.assertNotNull( botIF );
Object botInst = bot.newInstance();
Assert.assertNotNull( botInst );
OntoModelCompiler compiler2 = new OntoModelCompiler( results, folder.getRoot() );
compiler2.fixResolvedClasses();
compiler2.streamJavaInterfaces( false );
compiler2.streamXSDsWithBindings( true );
compiler2.mojo( OntoModelCompiler.defaultOptions, OntoModelCompiler.MOJO_VARIANTS.JPA2 );
showDirContent( folder );
File unImplBoundLeft = new File( compiler2.getXjcDir() + File.separator +
"org.jboss.drools.semantics.diamond".replace( ".", File.separator ) +
File.separator + "Left.java" );
assertFalse( unImplBoundLeft.exists() );
File implBoundLeft = new File( compiler2.getXjcDir() + File.separator +
"org.jboss.drools.semantics.diamond".replace( ".", File.separator ) +
File.separator + "LeftImpl.java" );
assertTrue( implBoundLeft.exists() );
File leftInterface = new File( compiler2.getJavaDir() + File.separator +
"org.jboss.drools.semantics.diamond".replace( ".", File.separator ) +
File.separator + "Left.java" );
assertTrue( leftInterface.exists() );
List<Diagnostic<? extends JavaFileObject>> diagnostics = compiler2.doCompile();
for ( Diagnostic<?> dx : diagnostics ) {
System.out.println( dx );
assertFalse( dx.getKind() == Diagnostic.Kind.ERROR );
}
showDirContent( folder );
Document dox = parseXML( new File( compiler2.getBinDir().getPath() + "/META-INF/persistence.xml" ), false );
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile( "//persistence-unit/@name" );
assertEquals( "diamondX", (String) expr.evaluate( dox, XPathConstants.STRING ) );
File YInterface = new File( compiler2.getJavaDir() + File.separator +
"org.jboss.drools.semantics.diamond".replace( ".", File.separator ) +
File.separator + "X.java" );
assertTrue( YInterface.exists() );
Class colf = Class.forName( "some.dependency.test.ChildOfLeftImpl", true, urlKL );
Assert.assertNotNull( colf );
Object colfInst = colf.newInstance();
List<String> hierarchy = getHierarchy( colf );
assertTrue( hierarchy.contains( "some.dependency.test.ChildOfLeftImpl" ) );
assertTrue( hierarchy.contains( "some.dependency.test.org.jboss.drools.semantics.diamond.LeftImpl" ) );
assertTrue( hierarchy.contains( "org.jboss.drools.semantics.diamond.LeftImpl" ) );
assertTrue( hierarchy.contains( "org.jboss.drools.semantics.diamond.C0Impl" ) );
assertTrue( hierarchy.contains( "org.jboss.drools.semantics.diamond.TopImpl" ) );
assertTrue( hierarchy.contains( "org.w3._2002._07.owl.ThingImpl" ) );
Set<String> itfHierarchy = getIFHierarchy( colf );
System.err.println( itfHierarchy.containsAll( Arrays.asList(
"org.jboss.drools.semantics.diamond.C1",
"org.jboss.drools.semantics.diamond.C0",
"some.dependency.test.org.jboss.drools.semantics.diamond.Left",
"some.dependency.test.ChildOfLeft",
"org.jboss.drools.semantics.diamond.Left",
"org.jboss.drools.semantics.diamond.Top",
"com.clarkparsia.empire.EmpireGenerated",
"org.w3._2002._07.owl.Thing",
"java.io.Serializable",
"org.drools.semantics.Thing",
"com.clarkparsia.empire.SupportsRdfId" ) ) );
Method getter1 = colf.getMethod( "getAnotherLeftProp" );
assertNotNull( getter1 );
Method getter2 = colf.getMethod( "getImportantProp");
assertNotNull( getter2 );
for ( Method m : colf.getMethods() ) {
if ( m.getName().equals( "addImportantProp" ) ) {
m.getName();
}
}
Method adder = colf.getMethod( "addImportantProp", botIF );
assertNotNull( adder );
adder.invoke( colfInst, botInst );
List l = (List) getter2.invoke( colfInst );
assertEquals( 1, l.size() );
File off = new File( compiler2.getXjcDir() + File.separator +
"org.jboss.drools.semantics.diamond".replace( ".", File.separator ) +
File.separator + "Left_Off.java" );
assertFalse( off.exists() );
testPersistenceWithInstance( urlKL, "org.jboss.drools.semantics.diamond.Bottom", diamond.getName() );
System.out.println(" Done" );
} catch ( Exception e ) {
e.printStackTrace();
fail( e.getMessage() );
}
}
private Set<String> getIFHierarchy( Class x ) {
Set<String> l = new HashSet<String>();
extractInterfaces( x, l );
return l;
}
private void extractInterfaces( Class x, Set<String> l ) {
for ( Class itf : x.getInterfaces() ) {
l.add( itf.getName() );
extractInterfaces( itf, l );
}
}
private List<String> getHierarchy( Class x ) {
List<String> l = new LinkedList<String>();
Class k = x;
while ( ! k.equals( Object.class ) ) {
l.add( k.getName() );
k = k.getSuperclass();
}
return l;
}
private void testPersistenceWithInstance( ClassLoader urlKL, String cName, String pUnit ) {
Object bot = null;
try {
bot = createTestFact( urlKL, cName );
} catch ( Exception e ) {
e.printStackTrace();
fail( e.getMessage() );
}
if ( bot != null ) {
checkJaxbRefresh( bot, urlKL );
checkEmpireRefresh( bot, urlKL );
checkSQLRefresh( bot, urlKL, pUnit );
checkJenaBeansRefresh( bot, urlKL );
}
}
private void checkJenaBeansRefresh( Object bot, ClassLoader urlk ) {
ClassLoader oldKL = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader( urlk );
OntModel m = ModelFactory.createOntologyModel();
Jenabean.instance().bind(m);
Jenabean.instance().writer().saveDeep(bot);
m.write(System.err);
Object x = Jenabean.instance().reader().load( bot.getClass(), ((UIdAble) bot).getDyEntryId() );
try {
checkEquality( bot, x );
} catch ( Exception e ) {
e.printStackTrace();
Assert.fail( e.getMessage() );
}
} finally {
Thread.currentThread().setContextClassLoader( oldKL );
}
}
private void checkSQLRefresh( Object obj, ClassLoader urlk, String punit ) {
ClassLoader oldKL = Thread.currentThread().getContextClassLoader();
EntityManagerFactory emf = null;
EntityManager em = null;
try {
Thread.currentThread().setContextClassLoader( urlk );
HashMap props = new HashMap();
props.put( "hibernate.hbm2ddl.auto", "create-drop" );
emf = Persistence.createEntityManagerFactory(
punit, props
);
em = emf.createEntityManager();
checkJPARefresh( obj,
((UIdAble) obj).getDyEntryId(),
em );
} finally {
Thread.currentThread().setContextClassLoader( oldKL );
if ( em != null && em.isOpen() ) {
em.clear();
em.close();
}
if ( emf != null && emf.isOpen() ) {
emf.close();
}
}
}
private void checkEmpireRefresh( Object obj, ClassLoader urlk ) {
File config = new File( compiler.getBinDir() + File.separator + compiler.METAINF + File.separator + "empire.configuration.file" );
File annox = new File( compiler.getBinDir() + File.separator + compiler.METAINF + File.separator + "empire.annotation.index" );
ClassLoader oldKL = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader( urlk );
checkJPARefresh( obj,
((UIdAble) obj).getRdfId(),
initEmpireEM(config, annox, obj.getClass().getPackage().getName()));
} finally {
Thread.currentThread().setContextClassLoader( oldKL );
}
}
private void checkJPARefresh( Object obj, Object key, EntityManager em ) {
persist( obj, em );
Object obj2 = refreshOnJPA( obj, key, em );
System.out.println( obj2 );
try {
checkEquality( obj, obj2 );
} catch ( Exception e ) {
e.printStackTrace();
fail( e.getMessage() );
}
}
private void checkEquality(Object obj, Object obj2) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Object c0 = obj2.getClass().getMethod( "getC0Prop" ).invoke( obj2 );
assertTrue( c0 instanceof List && ((List) c0).size() == 2 );
Object cX = obj2.getClass().getMethod( "getObjPropX" ).invoke( obj2 );
assertNotNull( cX );
System.out.println( cX );
assertTrue( cX.getClass().getName().endsWith( "XImpl" ) );
Object c2 = obj2.getClass().getMethod( "getC2Prop" ).invoke( obj2 );
assertTrue( c2 instanceof List
&& ((List) c2).size() == 1
&& ((List) c2).get( 0 ) instanceof String
);
}
private EntityManager initEmpireEM( File config, File annox, String pack ) {
System.setProperty( "empire.configuration.file", config.getPath() );
EmpireConfiguration ecfg = new EmpireConfiguration();
ecfg.getGlobalConfig().put( ConfigKeys.ANNOTATION_INDEX, annox.getPath() );
Empire.init( ecfg, new OpenRdfEmpireModule() );
EmpireOptions.STRICT_MODE = false;
PersistenceProvider aProvider = Empire.get().persistenceProvider();
EntityManagerFactory emf = aProvider.createEntityManagerFactory( pack, getTestEMConfigMap() );
EntityManager em = emf.createEntityManager();
return em;
}
private static Map<String, String> getTestEMConfigMap() {
Map<String, String> aMap = new HashMap<String, String>();
aMap.put(ConfigKeys.FACTORY, RepositoryDataSourceFactory.class.getName());
aMap.put(RepositoryDataSourceFactory.REPO, "test-repo");
aMap.put(RepositoryDataSourceFactory.FILES, "");
aMap.put(RepositoryDataSourceFactory.QUERY_LANG, RepositoryDataSourceFactory.LANG_SERQL);
return aMap;
}
private void persist( Object o, EntityManager em ) {
em.getTransaction().begin();
em.persist( o );
em.getTransaction().commit();
em.clear();
}
private Object refreshOnJPA( Object o, Object key, EntityManager em ) {
Object ret = null;
em.getTransaction().begin();
ret = em.find( o.getClass(), key );
em.getTransaction().commit();
return ret;
}
private Object createTestFact( ClassLoader urlKL, String cName ) throws Exception {
Class bottom = Class.forName( cName, true, urlKL );
Class bottomImpl = Class.forName( cName + "Impl", true, urlKL );
Object bot = bottomImpl.newInstance();
assertTrue( bottom.isAssignableFrom( bot.getClass() ) );
assertNotNull( bottomImpl.getMethod( "getObjPropX" ) );
assertNotNull( bottomImpl.getMethod( "getObjPropXs" ) );
Object ret = bottomImpl.getMethod( "getObjPropXs" ).invoke( bot );
assertNotNull( ret );
assertTrue( ret instanceof List );
assertEquals( 1, ( (List) ret ).size() );
bottom.getMethod( "addC1Prop", String.class ).invoke( bot, "helloc1" );
bottom.getMethod( "addC2Prop", String.class ).invoke( bot, "helloc2" );
bottom.getMethod( "addC0Prop", String.class ).invoke( bot, "helloc0" );
bottom.getMethod( "addC0Prop", String.class ).invoke( bot, "helloc0_2" );
return bot;
}
private void checkJaxbRefresh( Object obj, ClassLoader urlKL ) {
try {
JAXBContext jaxbContext;
jaxbContext = JAXBContext.newInstance( obj.getClass().getPackage().getName(), urlKL );
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty( Marshaller.JAXB_ENCODING, "UTF-8" );
marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
StringWriter sw = new StringWriter();
marshaller.marshal( obj, sw );
System.out.println( sw.toString() );
jaxbContext = JAXBContext.newInstance( obj.getClass().getPackage().getName(), urlKL );
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Marshaller marshaller2 = jaxbContext.createMarshaller();
marshaller2.setProperty( Marshaller.JAXB_ENCODING, "UTF-8" );
marshaller2.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
Object clone = unmarshaller.unmarshal( new StringReader( sw.toString() ) );
StringWriter sw2 = new StringWriter();
marshaller2.marshal( clone, sw2 );
System.err.println( sw2.toString() );
assertEquals( sw.toString(), sw2.toString() );
} catch ( PropertyException e ) {
e.printStackTrace();
fail( e.getMessage() );
} catch ( JAXBException e ) {
fail( e.getMessage() );
}
}
private void printSourceFile( File f, PrintStream out ) {
try {
FileInputStream fis = new FileInputStream( f );
byte[] buf = new byte[ fis.available() ];
fis.read( buf );
out.println(new String(buf));
} catch ( IOException ioe ) {
ioe.printStackTrace();
fail( ioe.getMessage() );
}
}
private Document parseXML( File f, boolean print ) throws IOException, ParserConfigurationException, SAXException, TransformerException {
InputSource xSource = new InputSource( new FileInputStream( f ) );
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
Document dox = null;
DocumentBuilder builder = dbf.newDocumentBuilder();
dox = builder.parse( xSource );
if ( print ) {
streamXML( dox, System.out );
}
return dox;
}
private void streamXML(Document dox, PrintStream out) throws TransformerException {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform( new DOMSource( dox ), new StreamResult( out ) );
}
private void showDirContent(TemporaryFolder folder) {
showDirContent( folder.getRoot(), 0 );
}
private void showDirContent( File file, int i ) {
System.out.println( tab(i) + " " + file.getName() );
if ( file.isDirectory() ) {
for ( File sub : file.listFiles() ) {
showDirContent( sub, i + 1 );
}
}
}
private String tab( int n ) {
return StringUtils.repeat( "\t", n );
}
}