All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpmml.xjc.PMMLPlugin Maven / Gradle / Ivy

/*
 * Copyright (c) 2009 University of Tartu
 */
package org.jpmml.xjc;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.XmlValue;

import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JCommentPart;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JDocComment;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JFieldRef;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JJavaName;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JMods;
import com.sun.codemodel.JStringLiteral;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.model.CAttributePropertyInfo;
import com.sun.tools.xjc.model.CClassInfo;
import com.sun.tools.xjc.model.CDefaultValue;
import com.sun.tools.xjc.model.CPropertyInfo;
import com.sun.tools.xjc.model.Model;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.FieldOutline;
import com.sun.tools.xjc.outline.Outline;
import org.eclipse.persistence.oxm.annotations.XmlValueExtension;
import org.xml.sax.ErrorHandler;

public class PMMLPlugin extends Plugin {

	@Override
	public String getOptionName(){
		return "Xpmml";
	}

	@Override
	public String getUsage(){
		return null;
	}

	@Override
	public void postProcessModel(Model model, ErrorHandler errorHandler){
		super.postProcessModel(model, errorHandler);

		Comparator comparator = new Comparator(){

			@Override
			public int compare(CPropertyInfo left, CPropertyInfo right){
				boolean leftAttribute = (left instanceof CAttributePropertyInfo);
				boolean rightAttribute = (right instanceof CAttributePropertyInfo);

				if(leftAttribute && !rightAttribute){
					return -1;
				} else

				if(!leftAttribute && rightAttribute){
					return 1;
				}

				return 0;
			}
		};

		Collection classInfos = (model.beans()).values();
		for(CClassInfo classInfo : classInfos){
			List propertyInfos = classInfo.getProperties();
			Collections.sort(propertyInfos, comparator);

			for(CPropertyInfo propertyInfo : propertyInfos){
				String publicName = propertyInfo.getName(true);
				String privateName = propertyInfo.getName(false);

				// Collection of values
				if(propertyInfo.isCollection()){

					if((privateName).contains("And") || (privateName).contains("Or") || (privateName).equalsIgnoreCase("content")){
						propertyInfo.setName(true, "Content");
						propertyInfo.setName(false, "content");
					} else

					{
						// Have "arrays" instead of "arraies"
						if((privateName).endsWith("array") || (privateName).endsWith("Array")){
							publicName += "s";
							privateName += "s";
						} else

						// Have "refs" instead of "reves"
						if((privateName).endsWith("ref") || (privateName).endsWith("Ref")){
							publicName += "s";
							privateName += "s";
						} else

						{
							publicName = JJavaName.getPluralForm(publicName);
							privateName = JJavaName.getPluralForm(privateName);
						}

						propertyInfo.setName(true, publicName);
						propertyInfo.setName(false, privateName);
					}
				} else

				// Simple value
				{
					if((privateName).equals("isScorable")){
						propertyInfo.setName(true, "Scorable");
						propertyInfo.setName(false, "scorable");
					}

					CDefaultValue defaultValue = propertyInfo.defaultValue;
					if(defaultValue != null){
						propertyInfo.defaultValue = new CShareableDefaultValue(propertyInfo, propertyInfo.defaultValue);
					}
				}
			}
		}
	}

	@Override
	public boolean run(Outline outline, Options options, ErrorHandler errorHandler){
		Model model = outline.getModel();

		JCodeModel codeModel = model.codeModel;

		JClass iterableInterface = codeModel.ref("java.lang.Iterable");
		JClass iteratorInterface = codeModel.ref("java.util.Iterator");

		JClass hasExtensionsInterface = codeModel.ref("org.dmg.pmml.HasExtensions");

		JClass arraysClass = codeModel.ref("java.util.Arrays");

		JClass fieldNameClass = codeModel.ref("org.dmg.pmml.FieldName");

		Collection clazzes = outline.getClasses();
		for(ClassOutline clazz : clazzes){
			JDefinedClass beanClazz = clazz.implClass;

			// Implementations of org.dmg.pmml.HasValue
			if(checkType(beanClazz, "org.dmg.pmml.CategoricalPredictor")){
				JMethod fieldMethod = beanClazz.method(JMod.PUBLIC, fieldNameClass, "getField");
				fieldMethod.annotate(Override.class);
				fieldMethod.body()._return(JExpr.invoke("getName"));
			} else

			if(checkType(beanClazz, "org.dmg.pmml.PPCell")){
				JMethod fieldMethod = beanClazz.method(JMod.PUBLIC, fieldNameClass, "getField");
				fieldMethod.annotate(Override.class);
				fieldMethod.body()._return(JExpr.invoke("getPredictorName"));
			} // End if

			// Implementations of org.dmg.pmml.Indexable
			if(checkType(beanClazz, "org.dmg.pmml.DefineFunction") || checkType(beanClazz, "org.dmg.pmml.Parameter")){
				JMethod keyMethod = beanClazz.method(JMod.PUBLIC, String.class, "getKey");
				keyMethod.annotate(Override.class);
				keyMethod.body()._return(JExpr.invoke("getName"));
			} else

			if(checkType(beanClazz, "org.dmg.pmml.MiningField")){
				JMethod keyMethod = beanClazz.method(JMod.PUBLIC, fieldNameClass, "getKey");
				keyMethod.annotate(Override.class);
				keyMethod.body()._return(JExpr.invoke("getName"));
			} else

			if(checkType(beanClazz, "org.dmg.pmml.InstanceField") || checkType(beanClazz, "org.dmg.pmml.Target") || checkType(beanClazz, "org.dmg.pmml.VerificationField")){
				JMethod keyMethod = beanClazz.method(JMod.PUBLIC, fieldNameClass, "getKey");
				keyMethod.annotate(Override.class);
				keyMethod.body()._return(JExpr.invoke("getField"));
			} else

			if(checkType(beanClazz, "org.dmg.pmml.Item") || checkType(beanClazz, "org.dmg.pmml.Itemset") || checkType(beanClazz, "org.dmg.pmml.Sequence") || checkType(beanClazz, "org.dmg.pmml.TextDocument") || checkType(beanClazz, "org.dmg.pmml.VectorInstance")){
				JMethod keyMethod = beanClazz.method(JMod.PUBLIC, String.class, "getKey");
				keyMethod.annotate(Override.class);
				keyMethod.body()._return(JExpr.invoke("getId"));
			} else

			if(checkType(beanClazz, "org.dmg.pmml.Value")){
				JMethod keyMethod = beanClazz.method(JMod.PUBLIC, String.class, "getKey");
				keyMethod.annotate(Override.class);
				keyMethod.body()._return(JExpr.invoke("getValue"));
			} // End if

			if(checkType(beanClazz, "org.dmg.pmml.Node")){
				JMethod hasScoreMethod = beanClazz.method(JMod.PUBLIC, boolean.class, "hasScore");
				hasScoreMethod.body()._return(JExpr.refthis("score").ne(JExpr._null()));
			}

			Map fieldVars = beanClazz.fields();

			FieldOutline contentField = getContentField(clazz);
			if(contentField != null){
				CPropertyInfo propertyInfo = contentField.getPropertyInfo();

				JFieldVar fieldVar = fieldVars.get(propertyInfo.getName(false));

				JType elementType = CodeModelUtil.getElementType(fieldVar.type());

				beanClazz._implements(iterableInterface.narrow(elementType));

				JMethod iteratorMethod = beanClazz.method(JMod.PUBLIC, iteratorInterface.narrow(elementType), "iterator");
				iteratorMethod.body()._return(JExpr.invoke("get" + propertyInfo.getName(true)).invoke("iterator"));
			}

			FieldOutline extensionsField = getExtensionsField(clazz);
			if(extensionsField != null){
				beanClazz._implements(hasExtensionsInterface);
			}

			FieldOutline[] fields = clazz.getDeclaredFields();
			for(FieldOutline field : fields){
				CPropertyInfo propertyInfo = field.getPropertyInfo();

				JFieldVar fieldVar = fieldVars.get(propertyInfo.getName(false));

				JMods modifiers = fieldVar.mods();
				if((modifiers.getValue() & JMod.PRIVATE) != JMod.PRIVATE){
					modifiers.setPrivate();
				}

				JType type = fieldVar.type();

				CShareableDefaultValue defaultValue = (CShareableDefaultValue)propertyInfo.defaultValue;
				if(defaultValue != null){

					if(defaultValue.isShared()){
						beanClazz.field(JMod.PRIVATE | JMod.STATIC | JMod.FINAL, fieldVar.type(), defaultValue.getField(), defaultValue.computeInit(outline));
					}
				}

				JMethod getterMethod = beanClazz.getMethod("get" + propertyInfo.getName(true), new JType[0]);
				JMethod setterMethod = beanClazz.getMethod("set" + propertyInfo.getName(true), new JType[]{type});

				if(getterMethod != null){
					JType returnType = getterMethod.type();

					if(returnType.isPrimitive() && !type.isPrimitive()){
						JType boxifiedReturnType = returnType.boxify();

						if((boxifiedReturnType).equals(type)){
							getterMethod.type(boxifiedReturnType);
						}
					}
				} // End if

				if(setterMethod != null){
					setterMethod.type(beanClazz);

					JVar param = (setterMethod.params()).get(0);

					String paramName = param.name();

					param.name(fieldVar.name());

					JDocComment javadoc = setterMethod.javadoc();

					try {
						Field atParamsField = JDocComment.class.getDeclaredField("atParams");
						if(!atParamsField.isAccessible()){
							atParamsField.setAccessible(true);
						}

						Map atParams = (Map)atParamsField.get(javadoc);

						JCommentPart paramComment = atParams.remove(paramName);
						if(paramComment != null){
							atParams.put(fieldVar.name(), paramComment);
						}
					} catch(ReflectiveOperationException roe){
						throw new RuntimeException(roe);
					}

					setterMethod.body()._return(JExpr._this());
				} // End if

				if(propertyInfo.isCollection()){
					JType elementType = CodeModelUtil.getElementType(type);

					JFieldRef fieldRef = JExpr.refthis(fieldVar.name());

					JMethod hasElementsMethod = beanClazz.method(JMod.PUBLIC, boolean.class, "has" + propertyInfo.getName(true));
					hasElementsMethod.body()._return((fieldRef.ne(JExpr._null())).cand((fieldRef.invoke("size")).gt(JExpr.lit(0))));

					JMethod addElementsMethod = beanClazz.method(JMod.PUBLIC, beanClazz, "add" + propertyInfo.getName(true));
					JVar param = addElementsMethod.varParam(elementType, fieldVar.name());
					addElementsMethod.body().add(JExpr.invoke(getterMethod).invoke("addAll").arg(arraysClass.staticInvoke("asList").arg(param)));
					addElementsMethod.body()._return(JExpr._this());
				}

				Collection annotations = fieldVar.annotations();

				if(hasAnnotation(annotations, XmlValue.class)){
					fieldVar.annotate(XmlValueExtension.class);
				}
			}
		}

		return true;
	}

	static
	private FieldOutline getExtensionsField(ClassOutline clazz){
		FieldFilter filter = new FieldFilter(){

			@Override
			public boolean accept(CPropertyInfo propertyInfo, JType type){

				if(("extensions").equals(propertyInfo.getName(false)) && propertyInfo.isCollection()){
					JType elementType = CodeModelUtil.getElementType(type);

					return checkType(elementType, "org.dmg.pmml.Extension");
				}

				return false;
			}
		};

		return findField(clazz, filter);
	}

	static
	private FieldOutline getContentField(final ClassOutline clazz){
		FieldFilter filter = new FieldFilter(){

			private String name = clazz.implClass.name();


			@Override
			public boolean accept(CPropertyInfo propertyInfo, JType type){

				if(propertyInfo.isCollection()){
					JType elementType = CodeModelUtil.getElementType(type);

					String name = elementType.name();

					return ((this.name).equals(name + "s") || (this.name).equals(JJavaName.getPluralForm(name)));
				}

				return false;
			}
		};

		return findField(clazz, filter);
	}

	static
	private FieldOutline findField(ClassOutline clazz, FieldFilter filter){
		FieldOutline[] fields = clazz.getDeclaredFields();

		for(FieldOutline field : fields){
			CPropertyInfo propertyInfo = field.getPropertyInfo();
			JType type = field.getRawType();

			if(filter.accept(propertyInfo, type)){
				return field;
			}
		}

		return null;
	}

	static
	private boolean hasAnnotation(Collection annotations, Class clazz){
		JAnnotationUse annotation = findAnnotation(annotations, clazz);

		return (annotation != null);
	}

	static
	private JAnnotationUse findAnnotation(Collection annotations, Class clazz){
		String fullName = clazz.getName();

		for(JAnnotationUse annotation : annotations){
			JClass type = annotation.getAnnotationClass();

			if(checkType(type, fullName)){
				return annotation;
			}
		}

		return null;
	}

	static
	private boolean checkType(JType type, String fullName){
		return (type.fullName()).equals(fullName);
	}

	static
	private interface FieldFilter {

		boolean accept(CPropertyInfo propertyInfo, JType type);
	}

	static
	private class CShareableDefaultValue extends CDefaultValue {

		private CDefaultValue parent = null;

		private String field = null;


		private CShareableDefaultValue(CPropertyInfo propertyInfo, CDefaultValue parent){
			setParent(parent);
			setField(formatField(propertyInfo.getName(false)));
		}

		@Override
		public JExpression compute(Outline outline){
			JExpression expression = computeInit(outline);

			if((expression instanceof JFieldRef) || (expression instanceof JStringLiteral)){
				setField(null);

				return expression;
			}

			return JExpr.ref(getField());
		}

		public JExpression computeInit(Outline outline){
			CDefaultValue parent = getParent();

			return parent.compute(outline);
		}

		public boolean isShared(){
			String field = getField();

			return (field != null);
		}

		public CDefaultValue getParent(){
			return this.parent;
		}

		private void setParent(CDefaultValue parent){
			this.parent = parent;
		}

		public String getField(){
			return this.field;
		}

		private void setField(String field){
			this.field = field;
		}

		static
		private String formatField(String string){
			StringBuilder sb = new StringBuilder();
			sb.append("DEFAULT_");

			for(int i = 0; i < string.length(); i++){
				char c = string.charAt(i);

				if(Character.isUpperCase(c)){
					sb.append('_');
				}

				sb.append(Character.toUpperCase(c));
			}

			return sb.toString();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy