/*
* 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.shapes;
import com.sun.codemodel.JDefinedClass;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.model.CPluginCustomization;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.Outline;
import org.drools.semantics.builder.model.compilers.SemanticXSDModelCompilerImpl;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import java.util.*;
public class AccessorPlugin extends Plugin {
public static String uri = "http://jboss.org/drools/drools-chance/drools-shapes/plugins/accessor";
public static String uri2 = "http://jboss.org/drools/drools-chance/drools-shapes/plugins/metadata";
private static String inferredGetterTempl = "inferredGetter";
public String getOptionName() {
return "Xsem-accessors";
}
public List<String> getCustomizationURIs() {
return Collections.singletonList( uri.toString() );
}
public boolean isCustomizationTagName( String nsUri, String localName ) {
return nsUri.equals( uri ) && ( localName.equals( "property" ) || localName.equals( "accessor" ) || localName.equals( "accessors" )
|| localName.equals( "chain" ) || localName.equals( "link" ) )
||
nsUri.equals( uri2 ) && (
localName.equals( "type" )
|| localName.equals( "property")
|| localName.equals( "restriction" ) );
}
public String getUsage() {
return " -Xsem-accessors";
}
@Override
public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) throws SAXException {
for (ClassOutline co : outline.getClasses() ) {
processBaseAccessors( co );
processInferredAccessors( co );
}
return true;
}
private void processInferredAccessors( ClassOutline co ) {
CPluginCustomization c = co.target.getCustomizations().find( uri2.toString(), "type" );
if( c == null ) {
return;
}
Element metaType = c.element;
NodeList propList = metaType.getChildNodes();
List<PropEssentials> props = new ArrayList<PropEssentials>();
for ( int j = 0; j < propList.getLength(); j++ ) {
Node n = propList.item( j );
if ( n instanceof Element ) {
Element el = (Element) n;
// if ( ! el.getTagName().equals( "property" ) ) { continue; }
String name = el.getAttribute( "name" );
String type = el.getAttribute( "type" );
String simp = el.getAttribute( "simple" );
PropEssentials prop = new PropEssentials( name, type, Boolean.valueOf( simp ) );
for ( int k = 0; k < el.getChildNodes().getLength(); k++ ) {
Node m = el.getChildNodes().item( k );
if ( m instanceof Element ) {
Element em = (Element) m;
// if ( ! em.getTagName().equals( "restriction" ) ) { continue; }
prop.addSub( new Sub( em.getAttribute( "name" ), em.getAttribute( "type" ), Boolean.valueOf( em.getAttribute( "single" ) ) ) );
}
}
props.add( prop );
}
}
HashMap<String, Object> map = new HashMap<String, Object>();
for ( PropEssentials prop : props ) {
map.put( "name", prop.getName() );
map.put( "type", prop.getType() );
map.put( "subs", prop.getSubs() );
map.put( "simple", prop.isSimple() );
String meta = SemanticXSDModelCompilerImpl.getTemplatedCode( inferredGetterTempl, map );
co.implClass.direct( meta );
}
c.markAsAcknowledged();
}
private void processBaseAccessors( ClassOutline co ) {
CPluginCustomization c = co.target.getCustomizations().find( uri, "accessors" );
if ( c== null ) {
return;
}
Element accessors = c.element;
NodeList props = accessors.getElementsByTagNameNS( uri, "property" );
for ( int j = 0; j < props.getLength(); j++ ) {
compileProperty( co.implClass, (Element) props.item( j ) );
}
createCycleManager(co.implClass);
NodeList axx = accessors.getElementsByTagNameNS( uri, "accessor" );
for ( int j = 0; j < axx.getLength(); j++ ) {
compileAccessor( co.implClass, (Element) axx.item( j ) );
}
c.markAsAcknowledged();
}
private void createCycleManager(JDefinedClass implClass) {
Map<String,Object> vars = new HashMap<String, Object>();
vars.put( "name", implClass.name().substring(0, implClass.name().length() - 4) ); //remove "Impl"
String method = SemanticXSDModelCompilerImpl.getTemplatedCode("onCycleDetected", vars);
implClass.direct(method);
}
private void compileProperty( JDefinedClass implClass, Element item ) {
Map<String,Object> vars = new HashMap<String, Object>();
vars.put( "name", item.getAttribute( "name" ) );
vars.put( "type", item.getAttribute( "type" ) );
vars.put( "max", null );
vars.put( "simple", Boolean.valueOf(item.getAttribute("simple")) );
vars.put( "primitive", Boolean.valueOf( item.getAttribute( "primitive" ) ) );
String code;
code = SemanticXSDModelCompilerImpl.getTemplatedCode("baseGetterSetter", vars);
implClass.direct( code );
code = SemanticXSDModelCompilerImpl.getTemplatedCode("baseAddRemove", vars);
implClass.direct( code );
code = SemanticXSDModelCompilerImpl.getTemplatedCode("genericAdd", vars);
implClass.direct( code );
}
private void compileAccessor( JDefinedClass implClass, Element item ) {
Map<String,Object> vars = new HashMap<String, Object>();
vars.put( "name", item.getAttribute( "name" ) );
vars.put( "type", item.getAttribute( "type" ) );
vars.put( "primitive", Boolean.valueOf( item.getAttribute( "primitive" ) ) );
vars.put( "min", Integer.valueOf( item.getAttribute( "min" ) ) );
vars.put( "max", item.getAttribute( "max" ).equals( "null") ? null : Integer.valueOf( item.getAttribute( "max" ) ) );
vars.put( "inherited", Boolean.valueOf( item.getAttribute( "inherited" ) ) );
vars.put( "base", item.getAttribute( "base" ) );
vars.put( "baseType", item.getAttribute( "baseType" ) );
vars.put( "simple", Boolean.valueOf(item.getAttribute("simple")) );
Set<List<Link>> chains = new HashSet<List<Link>>();
NodeList chainsList = item.getElementsByTagNameNS( uri, "chain");
for ( int j = 0; j < chainsList.getLength(); j++ ) {
List<Link> chain = new ArrayList<Link>();
NodeList linkList = ((Element) chainsList.item( j )).getElementsByTagNameNS( uri, "link" );
for ( int k = 0; k < linkList.getLength(); k++ ) {
Element link = (Element) linkList.item( k );
chain.add( new Link( link.getTextContent(), link.getAttribute( "type" ) ) );
}
chains.add( chain );
}
vars.put( "chains", chains );
vars.put( "isChained", chainsList.getLength() > 0 );
String code;
if ( chainsList.getLength() == 0 ) {
code = SemanticXSDModelCompilerImpl.getTemplatedCode("restrictedGetterSetter", vars);
implClass.direct( code );
} else {
code = SemanticXSDModelCompilerImpl.getTemplatedCode("chainGetter", vars);
implClass.direct( code );
}
if ( chainsList.getLength() == 0 ) {
code = SemanticXSDModelCompilerImpl.getTemplatedCode("restrictedAddRemove", vars);
implClass.direct( code );
}
}
public static class Sub {
private String name;
private String type;
private boolean single;
private Sub(String name, String type, boolean single) {
this.name = name;
this.single = single;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isSingle() {
return single;
}
public void setSingle(boolean single) {
this.single = single;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Sub sub = (Sub) o;
if (single != sub.single) return false;
if (name != null ? !name.equals(sub.name) : sub.name != null) return false;
if (type != null ? !type.equals(sub.type) : sub.type != null) return false;
return true;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (single ? 1 : 0);
result = 31 * result + type != null ? type.hashCode() : 0;
return result;
}
@Override
public String toString() {
return "Sub{" +
"name='" + name + '\'' +
", single=" + single +
'}';
}
}
public static class PropEssentials {
private String name;
private String type;
private boolean simple;
private List<Sub> subs;
public PropEssentials(String name, String type, boolean simple) {
this.name = name;
this.type = type;
this.simple = simple;
this.subs = new ArrayList<Sub>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Sub> getSubs() {
return subs;
}
public void addSub( Sub sub ) {
subs.add( sub );
}
public boolean isSimple() {
return simple;
}
public void setSimple(boolean simple) {
this.simple = simple;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PropEssentials that = (PropEssentials) o;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
if (type != null ? !type.equals(that.type) : that.type != null) return false;
return true;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (type != null ? type.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "PropEssentials{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
", subs=" + subs +
'}';
}
}
public static class Link {
private String name;
private String type;
public Link(String name, String type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
}