1 /*
   2  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.internal.xjc.api.impl.s2j;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Collection;
  30 import java.util.List;
  31 
  32 import javax.xml.namespace.QName;
  33 
  34 import com.sun.tools.internal.xjc.api.Mapping;
  35 import com.sun.tools.internal.xjc.api.Property;
  36 import com.sun.tools.internal.xjc.model.CClassInfo;
  37 import com.sun.tools.internal.xjc.model.CElement;
  38 import com.sun.tools.internal.xjc.model.CElementInfo;
  39 import com.sun.tools.internal.xjc.model.CElementPropertyInfo;
  40 import com.sun.tools.internal.xjc.model.CPropertyInfo;
  41 import com.sun.tools.internal.xjc.model.CReferencePropertyInfo;
  42 import com.sun.tools.internal.xjc.model.CTypeRef;
  43 import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
  44 import com.sun.xml.internal.bind.v2.model.core.ReferencePropertyInfo;
  45 
  46 import com.sun.xml.internal.xsom.XSComplexType;
  47 import com.sun.xml.internal.xsom.XSComponent;
  48 import com.sun.xml.internal.xsom.XSContentType;
  49 import com.sun.xml.internal.xsom.XSModelGroup;
  50 import com.sun.xml.internal.xsom.XSParticle;
  51 import com.sun.xml.internal.xsom.XSTerm;
  52 
  53 /**
  54  * Partial common implementation between {@link ElementMappingImpl} and {@link BeanMappingImpl}
  55  *
  56  * @author Kohsuke Kawaguchi
  57  */
  58 abstract class AbstractMappingImpl<InfoT extends CElement> implements Mapping {
  59 
  60     protected final JAXBModelImpl parent;
  61     protected final InfoT clazz;
  62     /**
  63      * Lazily computed.
  64      *
  65      * @see #getWrapperStyleDrilldown()
  66      */
  67     private List<Property> drilldown = null;
  68     private boolean drilldownComputed = false;
  69 
  70     protected AbstractMappingImpl(JAXBModelImpl parent, InfoT clazz) {
  71         this.parent = parent;
  72         this.clazz = clazz;
  73     }
  74 
  75     public final QName getElement() {
  76         return clazz.getElementName();
  77     }
  78 
  79     public final String getClazz() {
  80         return clazz.getType().fullName();
  81     }
  82 
  83     public final List<? extends Property> getWrapperStyleDrilldown() {
  84         if (!drilldownComputed) {
  85             drilldownComputed = true;
  86             drilldown = calcDrilldown();
  87         }
  88         return drilldown;
  89     }
  90 
  91     protected abstract List<Property> calcDrilldown();
  92 
  93     /**
  94      * Derived classes can use this method to implement {@link #calcDrilldown}.
  95      */
  96     protected List<Property> buildDrilldown(CClassInfo typeBean) {
  97         //JAXWS 2.1 spec 2.3.1.2:
  98         //Wrapper style if the wrapper elements only contain child elements,
  99         //they must not contain xsd:choice
 100         if (containingChoice(typeBean)) {
 101             return null;
 102         }
 103 
 104         List<Property> result;
 105 
 106         CClassInfo bc = typeBean.getBaseClass();
 107         if (bc != null) {
 108             result = buildDrilldown(bc);
 109             if (result == null) {
 110                 return null;        // aborted
 111             }
 112         } else {
 113             result = new ArrayList<Property>();
 114         }
 115 
 116         for (CPropertyInfo p : typeBean.getProperties()) {
 117             if (p instanceof CElementPropertyInfo) {
 118                 CElementPropertyInfo ep = (CElementPropertyInfo) p;
 119 // wrong. A+,B,C is eligible for drill-down.
 120 //                if(ep.isCollection())
 121 //                    // content model like A+,B,C is not eligible
 122 //                    return null;
 123 
 124                 List<? extends CTypeRef> ref = ep.getTypes();
 125                 if (ref.size() != 1) {// content model like (A|B),C is not eligible
 126                     return null;
 127                 }
 128 
 129                 result.add(createPropertyImpl(ep, ref.get(0).getTagName()));
 130             } else if (p instanceof ReferencePropertyInfo) {
 131                 CReferencePropertyInfo rp = (CReferencePropertyInfo) p;
 132 
 133                 Collection<CElement> elements = rp.getElements();
 134                 if (elements.size() != 1) {
 135                     return null;
 136                 }
 137 
 138                 CElement ref = elements.iterator().next();
 139                 if (ref instanceof ClassInfo) {
 140                     result.add(createPropertyImpl(rp, ref.getElementName()));
 141                 } else {
 142                     CElementInfo eref = (CElementInfo) ref;
 143                     if (!eref.getSubstitutionMembers().isEmpty()) {
 144                         return null;    // elements with a substitution group isn't qualified for the wrapper style
 145                     }
 146                     // JAX-WS doesn't want to see JAXBElement, so we have to hide it for them.
 147                     ElementAdapter fr;
 148                     if (rp.isCollection()) {
 149                         fr = new ElementCollectionAdapter(parent.outline.getField(rp), eref);
 150                     } else {
 151                         fr = new ElementSingleAdapter(parent.outline.getField(rp), eref);
 152                     }
 153 
 154                     result.add(new PropertyImpl(this,
 155                             fr, eref.getElementName()));
 156                 }
 157             } else {// to be eligible for the wrapper style, only elements are allowed.
 158                     // according to the JAX-RPC spec 2.3.1.2, element refs are disallowed
 159                 return null;
 160             }
 161 
 162         }
 163 
 164         return result;
 165     }
 166 
 167     private boolean containingChoice(CClassInfo typeBean) {
 168         XSComponent component = typeBean.getSchemaComponent();
 169         if (component instanceof XSComplexType) {
 170             XSContentType contentType = ((XSComplexType) component).getContentType();
 171             XSParticle particle = contentType.asParticle();
 172             if (particle != null) {
 173                 XSTerm term = particle.getTerm();
 174                 XSModelGroup modelGroup = term.asModelGroup();
 175                 if (modelGroup != null) {
 176                     return (modelGroup.getCompositor() == XSModelGroup.Compositor.CHOICE);
 177                 }
 178             }
 179         }
 180 
 181         return false;
 182     }
 183 
 184     private Property createPropertyImpl(CPropertyInfo p, QName tagName) {
 185         return new PropertyImpl(this,
 186                 parent.outline.getField(p), tagName);
 187     }
 188 }