/* * Copyright (c) 2010-2013 Evolveum * * 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 com.evolveum.midpoint.schema.xjc.clone; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismReferenceValue; import com.evolveum.midpoint.schema.xjc.Processor; import com.evolveum.midpoint.schema.xjc.schema.SchemaProcessor; import com.evolveum.midpoint.schema.xjc.util.ProcessorUtils; import com.sun.codemodel.*; import com.sun.tools.xjc.Options; import com.sun.tools.xjc.model.CClassInfo; import com.sun.tools.xjc.model.nav.NClass; import com.sun.tools.xjc.outline.ClassOutline; import com.sun.tools.xjc.outline.Outline; import net.sourceforge.ccxjc.PluginImpl; import org.xml.sax.ErrorHandler; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * @author lazyman */ public class CloneProcessor implements Processor { private static final String METHOD_CLONE = "clone"; @Override public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) throws Exception { PluginImpl clonePlugin = new PluginImpl(); clonePlugin.run(outline, opt, errorHandler); Set<Map.Entry<NClass, CClassInfo>> set = outline.getModel().beans().entrySet(); for (Map.Entry<NClass, CClassInfo> entry : set) { ClassOutline classOutline = outline.getClazz(entry.getValue()); if (isPrism(classOutline)) { removeConstructors(classOutline); removeCloneableMethod(classOutline); removePrivateStaticCopyMethods(classOutline); createCloneMethod(classOutline); } } return true; } private void removePrivateStaticCopyMethods(ClassOutline classOutline) { JDefinedClass impl = classOutline.implClass; Iterator<JMethod> methods = impl.methods().iterator(); while (methods.hasNext()) { JMethod method = methods.next(); if ((method.mods().getValue() & (JMod.PRIVATE | JMod.STATIC)) == 0) { continue; } if (method.name().startsWith("copy")) { methods.remove(); } } } private void removeConstructors(ClassOutline classOutline) { JDefinedClass impl = classOutline.implClass; Iterator<JMethod> constructors = impl.constructors(); while (constructors.hasNext()) { JMethod constructor = constructors.next(); if (constructor.hasSignature(new JType[]{impl}) /* || constructor.hasSignature(new JType[]{}) */) { // default constructor has to be kept there! constructors.remove(); } } } private void removeCloneableMethod(ClassOutline classOutline) { JDefinedClass impl = classOutline.implClass; Iterator<JMethod> methods = impl.methods().iterator(); while (methods.hasNext()) { JMethod method = methods.next(); if ("clone".equals(method.name()) && method.hasSignature(new JType[]{})) { methods.remove(); } } } private void createCloneMethod(ClassOutline classOutline) { JDefinedClass impl = classOutline.implClass; JMethod cloneMethod = impl.method(JMod.PUBLIC, impl, METHOD_CLONE); JBlock body = cloneMethod.body(); if (impl.isAbstract()) { body._return(JExpr._this()); //don't create clone() method body on abstract prism objects return; } Outline outline = classOutline.parent(); JVar object = body.decl(impl, "object", JExpr._new(impl)); if (ProcessorUtils.hasParentAnnotation(classOutline, SchemaProcessor.A_PRISM_OBJECT)) { JClass type = (JClass) outline.getModel().codeModel._ref(PrismObject.class); JVar prism = body.decl(type, "value", JExpr.invoke(SchemaProcessor.METHOD_AS_PRISM_OBJECT).invoke(METHOD_CLONE)); JInvocation invocation = object.invoke(SchemaProcessor.METHOD_SETUP_CONTAINER); invocation.arg(prism); body.add(invocation); } else if (ProcessorUtils.hasParentAnnotation(classOutline, SchemaProcessor.A_PRISM_CONTAINER)) { JClass type = (JClass) outline.getModel().codeModel._ref(PrismContainerValue.class); JVar prism = body.decl(type, "value", JExpr.invoke(SchemaProcessor.METHOD_AS_PRISM_CONTAINER_VALUE).invoke(METHOD_CLONE)); JInvocation invocation = object.invoke(SchemaProcessor.METHOD_SETUP_CONTAINER_VALUE); invocation.arg(prism); body.add(invocation); } else if (ProcessorUtils.hasParentAnnotation(classOutline, SchemaProcessor.A_OBJECT_REFERENCE)) { JClass type = (JClass) outline.getModel().codeModel._ref(PrismReferenceValue.class); JVar prism = body.decl(type, "value", JExpr.invoke(SchemaProcessor.METHOD_AS_REFERENCE_VALUE).invoke(METHOD_CLONE)); JInvocation invocation = object.invoke(SchemaProcessor.METHOD_SETUP_REFERENCE_VALUE); invocation.arg(prism); body.add(invocation); } body._return(object); } private boolean isPrism(ClassOutline classOutline) { return ProcessorUtils.hasParentAnnotation(classOutline, SchemaProcessor.A_PRISM_OBJECT) || ProcessorUtils.hasParentAnnotation(classOutline, SchemaProcessor.A_PRISM_CONTAINER) || ProcessorUtils.hasParentAnnotation(classOutline, SchemaProcessor.A_OBJECT_REFERENCE); } }