/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.sling.maven.jcrocm; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import org.apache.maven.plugin.logging.Log; import com.thoughtworks.qdox.model.DocletTag; import com.thoughtworks.qdox.model.JavaClass; /** * The <code>ClassDescriptor</code> class provides support for the * class-descriptor element of a class mapping, which has the following * attribute list definition: * * <pre> * <!ATTLIST class-descriptor * className CDATA #REQUIRED * jcrType CDATA #IMPLIED * jcrSuperTypes CDATA #IMPLIED * jcrMixinTypes CDATA #IMPLIED * extend CDATA #IMPLIED * abstract (true|false) "false" * interface (true|false) "false" * discriminator (true|false) "true" * > * <!ATTLIST implement-descriptor * interfaceName CDATA #REQUIRED * > * </pre> * * <p> * Additionally, as can be seen from above, the * <code>implement-descriptor</code> is also supported by this class. It * retrieves the list of interfaces from the described class. * </p> */ public class ClassDescriptor extends AbstractDescriptorElement { public static final String TAG_CLASS_DESCRIPTOR = "ocm.mapped"; public static final String ELEMENT_CLASS_DESCRIPTOR = "class-descriptor"; public static final String CLASS_NAME = "className"; public static final String JCR_TYPE = "jcrType"; public static final String JCR_SUPER_TYPES = "jcrSuperTypes"; public static final String JCR_MIXIN_TYPES = "jcrMixinTypes"; public static final String EXTEND = "extend"; public static final String INTERFACES = "interfaces"; public static final String ABSTRACT = "abstract"; public static final String INTERFACE = "interface"; public static final String DISCRIMINATOR = "discriminator"; public static final String ELEMENT_IMPLEMENT_DESCRIPTOR = "implement-descriptor"; public static final String INTERFACE_NAME = "interfaceName"; private String className; private String jcrType; private String jcrSuperTypes; private String jcrMixinTypes; private boolean discriminator = true; private String extend; private boolean isAbstract; private boolean isInterface; private Set interfaces; private List children; static ClassDescriptor fromClass(Log log, JavaClass javaClass) { DocletTag tag = javaClass.getTagByName(TAG_CLASS_DESCRIPTOR); if (tag == null) { return null; } ClassDescriptor cd = new ClassDescriptor(log, tag); cd.className = javaClass.getFullyQualifiedName(); cd.isInterface = javaClass.isInterface(); cd.isAbstract = !cd.isInterface && javaClass.isAbstract(); cd.extend = tag.getNamedParameter(EXTEND); if (cd.extend == null) { if (javaClass.getSuperJavaClass() != null) { cd.extend = javaClass.getSuperJavaClass().getFullyQualifiedName(); // do not declare extending Object :-) if (Object.class.getName().equals(cd.extend)) { cd.extend = null; } } } else if (cd.extend.length() == 0) { // explicit empty extend value prevents extend attribute from being // set cd.extend = null; } String interfaceList = tag.getNamedParameter(INTERFACES); if (interfaceList == null) { if (javaClass.getImplementedInterfaces() != null) { JavaClass[] implInterfaces = javaClass.getImplementedInterfaces(); cd.interfaces = new HashSet(); for (int i = 0; i < implInterfaces.length; i++) { cd.interfaces.add(implInterfaces[i].getFullyQualifiedName()); } } } else if (interfaceList.length() == 0) { // empty interface list prevents creation of interface element cd.interfaces = null; } else { // split list and create set for interface elements StringTokenizer tokener = new StringTokenizer(interfaceList, ","); cd.interfaces = new HashSet(); while (tokener.hasMoreTokens()) { String iface = tokener.nextToken().trim(); if (iface.length() > 0) { cd.interfaces.add(iface); } } } cd.jcrType = tag.getNamedParameter(JCR_TYPE); cd.jcrSuperTypes = tag.getNamedParameter(JCR_SUPER_TYPES); cd.jcrMixinTypes = tag.getNamedParameter(JCR_MIXIN_TYPES); // only reset default if explicitly stated if (tag.getNamedParameter(DISCRIMINATOR) != null) { cd.discriminator = Boolean.valueOf( tag.getNamedParameter(DISCRIMINATOR)).booleanValue(); } return cd; } private ClassDescriptor(Log log, DocletTag tag) { super(log, tag); } void addChild(AbstractDescriptorElement child) { if (child != null) { if (children == null) { children = new ArrayList(); } children.add(child); } } /* * (non-Javadoc) * * @see org.apache.sling.maven.jcrocm.AbstractDescriptorElement#generate(org.apache.sling.maven.jcrocm.XMLWriter) */ void generate(XMLWriter xmlWriter) { xmlWriter.println(); xmlWriter.printComment("Class: " + className); xmlWriter.printElementStart(ELEMENT_CLASS_DESCRIPTOR, true); xmlWriter.printAttribute(CLASS_NAME, className); xmlWriter.printAttribute(JCR_TYPE, jcrType); xmlWriter.printAttribute(JCR_SUPER_TYPES, jcrSuperTypes); xmlWriter.printAttribute(JCR_MIXIN_TYPES, jcrMixinTypes); xmlWriter.printAttribute(EXTEND, extend); xmlWriter.printAttribute(ABSTRACT, isAbstract); xmlWriter.printAttribute(INTERFACE, isInterface); // only write discriminator if false, true is the default here if (!discriminator) { xmlWriter.printAttribute(DISCRIMINATOR, "false"); } xmlWriter.printElementStartClose(false); // interface implementations if (interfaces != null) { for (Iterator ii = interfaces.iterator(); ii.hasNext();) { String iface = (String) ii.next(); xmlWriter.println(); xmlWriter.printElementStart(ELEMENT_IMPLEMENT_DESCRIPTOR, true); xmlWriter.printAttribute(INTERFACE_NAME, iface); xmlWriter.printElementStartClose(true); } } // fields, beans and collections if (children != null) { for (Iterator ci = children.iterator(); ci.hasNext();) { AbstractDescriptorElement child = (AbstractDescriptorElement) ci.next(); xmlWriter.println(); child.generate(xmlWriter); } } xmlWriter.printElementEnd(ELEMENT_CLASS_DESCRIPTOR); } /* * (non-Javadoc) * * @see org.apache.sling.maven.jcrocm.AbstractDescriptorElement#validate() */ boolean validate() { boolean valid = true; if (children != null) { if (children != null) { for (Iterator ci = children.iterator(); ci.hasNext();) { AbstractDescriptorElement child = (AbstractDescriptorElement) ci.next(); valid &= child.validate(); if (!valid) break; } } } return valid; } }