/*
* 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.builder.model.compilers;
import org.drools.io.ResourceFactory;
import org.drools.semantics.builder.DLTemplateManager;
import org.drools.semantics.utils.NameUtils;
import org.drools.semantics.builder.model.*;
import org.drools.semantics.utils.NamespaceUtils;
import org.jdom.Namespace;
import org.mvel2.templates.CompiledTemplate;
import org.mvel2.templates.TemplateRegistry;
import org.mvel2.templates.TemplateRuntime;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SemanticXSDModelCompilerImpl extends XSDModelCompilerImpl implements SemanticXSDModelCompiler {
private TemplateRegistry registry = DLTemplateManager.getDataModelRegistry( ModelFactory.CompileTarget.XSDX );
protected static final String semGetterTemplateName = "semGetter.drlt";
protected static final String semSetterTemplateName = "semSetter.drlt";
protected static final String propChainTemplateName = "propChainGetter.drlt";
private static CompiledTemplate gettt;
private static CompiledTemplate settt;
private static CompiledTemplate chant;
@Override
public CompiledOntoModel compile( OntoModel model ) {
SemanticXSDModel sxsdModel = (SemanticXSDModel) super.compile( model );
for ( Namespace ns : sxsdModel.getNamespaces() ) {
sxsdModel.setBindings( ns.getURI(), createBindings( ns.getURI(), sxsdModel ) );
}
mergeNamespacedPackageInfo( sxsdModel );
sxsdModel.setIndex( createIndex( sxsdModel ) );
sxsdModel.setIndividualFactory( compileIntoFactory( sxsdModel ) );
sxsdModel.setEmpireConfig( createEmpireConfig( Arrays.asList( sxsdModel.getName() ) ) );
sxsdModel.setPersistenceXml( createPersistenceXml() );
return sxsdModel;
}
private String createPersistenceXml() {
try {
String template = readFile( "persistence-template-hibernate.xml.template" );
Map<String,Object> vars = new HashMap<String, Object>();
String index = TemplateRuntime.eval( template, vars ).toString();
return index;
} catch ( Exception e ) {
e.printStackTrace();
return "";
}
}
private String createEmpireConfig( Collection<String> models ) {
try {
String template = readFile( "empire.configuration.file.template" );
Map<String,Object> vars = new HashMap<String, Object>();
vars.put( "index", "empire.annotation.index" );
vars.put( "models", models );
vars.put( "datasources", Arrays.asList( "sesame", "jena" ) );
String index = TemplateRuntime.eval( template, vars ).toString();
return index;
} catch ( Exception e ) {
e.printStackTrace();
return "";
}
}
private String createIndex( SemanticXSDModel sxsdModel ) {
try {
String template = readFile( "empire.annotation.index.template" );
Map<String,Object> vars = new HashMap<String, Object>();
vars.put( "klasses", sxsdModel.getConcepts() );
String index = TemplateRuntime.eval( template, vars ).toString();
return index;
} catch ( Exception e ) {
e.printStackTrace();
return "";
}
}
private String createNamespacedPackageInfo( Namespace ns, String packageName, Map<String,Namespace> prefixMap ) {
HashMap map = new HashMap();
map.put( "namespace", ns.getURI() );
map.put( "pack", packageName );
map.put( "prefixMap", prefixMap );
String fix = SemanticXSDModelCompilerImpl.getTemplatedCode( "package-info.java", map, ModelFactory.CompileTarget.JAVA );
return fix;
}
private String compileIntoFactory( SemanticXSDModel sxsdModel ) {
try {
Map<String,Object> vars = new HashMap<String, Object>();
vars.put( "package", sxsdModel.getDefaultPackage() );
vars.put( "individuals", sxsdModel.getIndividuals() );
String index = getTemplatedCode( "IndividualFactory", vars, ModelFactory.CompileTarget.JAVA );
return index;
} catch ( Exception e ) {
e.printStackTrace();
return "";
}
}
public ModelFactory.CompileTarget getCompileTarget() {
return ModelFactory.CompileTarget.XSDX;
}
private Document createBindings( String ns, SemanticXSDModel sxsdModel ) {
if ( "http://www.w3.org/2002/07/owl".equals( ns ) ) {
return getGlobalBindings();
}
String prefix = ((XSDModel) getModel()).mapNamespaceToPrefix( ns );
try {
String template = readFile( "bindings.xjb.template" );
Collection<Concept> cons = filterConceptsByNS( getModel().getConcepts(), ns );
cons = filterUnneedecConcepts( cons, model );
Map<String,Object> vars = new HashMap<String,Object>();
vars.put( "package", NameUtils.namespaceURIToPackage( ns ) );
vars.put( "namespace", ns );
vars.put( "concepts", cons );
vars.put( "flat", getModel().getMode() != OntoModel.Mode.HIERARCHY );
vars.put( "properties", propCache );
vars.put( "modelName", getModel().getName() );
vars.put( "schemaLocation", NameUtils.namespaceURIToPackage( ns ) );
// vars.put( "schemaLocation", getModel().getName() + ( prefix == null ? "" : ( "_" + prefix ) ) );
vars.put( "extra_code", prepareCodeExtensions( sxsdModel ) );
String bindings = TemplateRuntime.eval( template, NameUtils.getInstance(), vars ).toString();
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
Document dox = df.newDocumentBuilder().parse( new InputSource( new StringReader( bindings ) ) );
dox.normalizeDocument();
return dox;
} catch ( Exception ioe ) {
ioe.printStackTrace();
return null;
}
}
private Collection<Concept> filterUnneedecConcepts( Collection<Concept> cons, CompiledOntoModel model ) {
ArrayList<Concept> filtered = new ArrayList<Concept>( cons.size() );
for ( Concept c : cons ) {
if ( model.getMode() != OntoModel.Mode.FLAT && model.getMode() != OntoModel.Mode.NONE && model.getMode() != OntoModel.Mode.DATABASE ) {
filtered.add( c );
} else {
if ( ! c.isAbstrakt() ) {
filtered.add( c );
}
}
}
return filtered;
}
public void mergeNamespacedPackageInfo( SemanticXSDModel model ) {
for ( Namespace ns : model.getNamespaces() ) {
String info = createNamespacedPackageInfo( ns, NameUtils.namespaceURIToPackage( ns.getURI() ), model.getAssignedPrefixes() );
model.addNamespacedPackageInfo( ns, info );
}
}
public void mergeEmpireConfig( File preexistingEmpireConfig, SemanticXSDModel model ) {
try {
FileInputStream bis = new FileInputStream( preexistingEmpireConfig );
byte[] an = new byte[ bis.available() ];
bis.read( an );
Set<String> matchSet = new HashSet<String>();
Pattern regex = Pattern.compile( "\\d.name = (.+)-sesame-data-source", Pattern.MULTILINE );
Matcher regexMatcher;
regexMatcher = regex.matcher( new String( an ) );
while ( regexMatcher.find() ) {
matchSet.add( regexMatcher.group( 1 ) );
}
regexMatcher = regex.matcher( model.getEmpireConfig() );
while ( regexMatcher.find() ) {
matchSet.add( regexMatcher.group( 1 ) );
}
String config = createEmpireConfig( matchSet );
model.setEmpireConfig( config );
} catch ( FileNotFoundException e ) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch ( IOException e ) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
public void mergeIndex( File preexistingIndex, SemanticXSDModel model ) {
FileInputStream bis = null;
try {
bis = new FileInputStream( preexistingIndex );
byte[] an = new byte[ bis.available() ];
bis.read( an );
String old = new String( an );
String nju = model.getIndex();
Set<String> oldTypes = new HashSet<String>();
int j = old.indexOf( "javax.persistence.NamedQuery=" ) -1;
StringBuilder newIndex = new StringBuilder();
newIndex.append( old.substring( 0, j ) );
StringTokenizer tok = new StringTokenizer( old, "=,\n" );
while ( tok.hasMoreTokens() ) {
oldTypes.add( tok.nextToken() );
}
tok = new StringTokenizer( nju, "=,\n" );
while ( tok.hasMoreTokens() ) {
String t = tok.nextToken();
if ( ! oldTypes.contains( t ) ) {
newIndex.append( "," ).append( tok.nextToken() );
}
}
newIndex.append( old.substring( j ) );
// System.out.println( "OLD INDEX " + old );
// System.out.println( "NEW INDEX " + newIndex );
model.setIndex( newIndex.toString() );
} catch ( Exception e ) {
e.printStackTrace();
}
}
// public void mergePersistenceXml( File preexistingPersistenceXml, SemanticXSDModel model ) {
// FileInputStream bis = null;
// try {
// bis = new FileInputStream( preexistingPersistenceXml );
// byte[] an = new byte[ bis.available() ];
// bis.read( an );
//
// String old = new String( an );
//
// System.out.println( "OLD PERX " + old );
// System.out.println( "NEW PERX " + model.getPersistenceXml() );
// } catch ( Exception e ) {
// e.printStackTrace();
// }
//
// throw new UnsupportedOperationException( "TODO" );
// }
private Collection<Concept> filterConceptsByNS( List<Concept> concepts, String ns ) {
List<Concept> filtered = new ArrayList<Concept>();
for ( Concept con : concepts ) {
if ( NamespaceUtils.compareNamespaces(con.getNamespace(), ns) ) {
filtered.add( con );
}
}
return filtered;
}
private Map<String,String> prepareCodeExtensions( SemanticXSDModel sxsdModel ) {
Map<String,String> code = new HashMap<String, String>( sxsdModel.getConcepts().size() );
List<Concept> filteredConcepts = sxsdModel.getConcepts();
for ( Concept con : filteredConcepts ) {
StringBuilder sb = new StringBuilder("");
Map<String, Set<PropertyRelation>> restrictions = buildRestrictionMatrix( con.getProperties().values() );
for ( String propKey : con.getProperties().keySet() ) {
PropertyRelation prop = con.getProperties().get( propKey );
if ( ! prop.isRestricted() && ! prop.isTransient() ) {
String setter = prop.getSetter();
String adder = prop.getSetter().replace( "set", "add" );
String toggler = prop.getSetter().replace( "set", "remove" );
Map<String,Object> vars = new HashMap<String, Object>();
vars.put( "typeName", prop.getTypeName() );
vars.put( "isSimpleBoolean", prop.isSimpleBoolean() );
vars.put( "isCollection", prop.isCollection() );
vars.put( "name", prop.getName() );
vars.put( "getter", prop.getGetter() );
vars.put( "setter", setter );
vars.put( "adder", adder );
vars.put( "toggler", toggler );
vars.put( "min", prop.getMinCard() );
vars.put( "max", prop.getMaxCard() );
Set<PropertyRelation> restrs = restrictions.get( prop.getName() );
vars.put( "restrictions", restrs != null ? restrs : Collections.emptySet() );
// String getProperty = TemplateRuntime.execute( getGetterTemplate(), NameUtils.getInstance(), vars ).toString();
//
// sb.append( getProperty );
//
// String setProperty = TemplateRuntime.execute( getSetterTemplate(), NameUtils.getInstance(), vars ).toString();
//
// sb.append( setProperty );
} else {
if ( prop.isChain() ) {
Map<String,Object> vars = new HashMap<String, Object>();
vars.put( "typeName", prop.getTypeName() );
vars.put( "isSimpleBoolean", prop.isSimpleBoolean() );
vars.put( "isCollection", prop.isCollection() );
vars.put( "getter", prop.getGetter() );
vars.put( "min", prop.getMinCard() );
vars.put( "max", prop.getMaxCard() );
vars.put( "chains", prop.getChains() );
// String getChain = TemplateRuntime.execute( getChainTemplate(), NameUtils.getInstance(), vars ).toString();
//
// sb.append( getChain );
}
}
}
code.put( con.getName(), sb.toString() );
//code.put( con.getName(), "" );
}
return code;
}
private Map<String, Set<PropertyRelation>> buildRestrictionMatrix( Collection<PropertyRelation> rels ) {
Map<String, Set<PropertyRelation>> matrix = new HashMap<String, Set<PropertyRelation>>();
for ( PropertyRelation rel : rels ) {
if ( rel.isRestricted() ) {
Set<PropertyRelation> others = matrix.get( rel.getBaseProperty().getName() );
if ( others == null ) {
others = new HashSet<PropertyRelation>();
matrix.put( rel.getBaseProperty().getName(), others );
}
others.add( rel );
}
}
return matrix;
}
protected CompiledTemplate getChainTemplate() {
if ( chant == null ) {
chant = DLTemplateManager.getDataModelRegistry( ModelFactory.CompileTarget.XSDX ).getNamedTemplate( propChainTemplateName );
}
return chant;
}
protected CompiledTemplate getGetterTemplate() {
if ( gettt == null ) {
gettt = DLTemplateManager.getDataModelRegistry( ModelFactory.CompileTarget.XSDX ).getNamedTemplate( semGetterTemplateName );
}
return gettt;
}
protected CompiledTemplate getSetterTemplate() {
if ( settt == null ) {
settt = DLTemplateManager.getDataModelRegistry( ModelFactory.CompileTarget.XSDX ).getNamedTemplate( semSetterTemplateName );
}
return settt;
}
private static String readFile(String name) throws IOException {
String fullPath = SemanticXSDModelCompiler.class.getPackage().getName().replace( ".", "/" )
+ "/"
+ name;
InputStream stream = ResourceFactory.newClassPathResource( fullPath ).getInputStream();
try {
byte[] data = new byte[ stream.available() ];
stream.read(data);
return new String( data );
}
finally {
stream.close();
}
}
public static String getTemplatedCode( String template, Map<String, Object> vars ) {
return getTemplatedCode( template, vars, ModelFactory.CompileTarget.XSDX );
}
public static String getTemplatedCode( String template, Map<String, Object> vars, ModelFactory.CompileTarget target ) {
return TemplateRuntime.execute (
DLTemplateManager.getDataModelRegistry( target ).getNamedTemplate( template + ".template" ),
NameUtils.getInstance(),
vars ).toString();
}
public Document getGlobalBindings() {
InputStream bindingsIS = null;
try {
bindingsIS = ResourceFactory.newClassPathResource("org/drools/semantics/builder/model/compilers/global.xjb").getInputStream();
byte[] data = new byte[ bindingsIS.available() ];
bindingsIS.read( data );
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
return df.newDocumentBuilder().parse( new ByteArrayInputStream( data ) );
} catch ( Exception e ) {
e.printStackTrace();
return null;
}
}
}