1 /*
   2  * Copyright (c) 1997, 2012, 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.model;
  27 
  28 import java.util.Collection;
  29 import java.util.HashSet;
  30 import java.util.Set;
  31 import java.util.Map;
  32 
  33 import javax.activation.MimeType;
  34 import javax.xml.bind.annotation.W3CDomHandler;
  35 import javax.xml.namespace.QName;
  36 
  37 import com.sun.tools.internal.xjc.model.nav.NClass;
  38 import com.sun.tools.internal.xjc.model.nav.NType;
  39 import com.sun.tools.internal.xjc.model.nav.NavigatorImpl;
  40 import com.sun.xml.internal.bind.v2.model.core.ID;
  41 import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
  42 import com.sun.xml.internal.bind.v2.model.core.ReferencePropertyInfo;
  43 import com.sun.xml.internal.bind.v2.model.core.WildcardMode;
  44 import com.sun.xml.internal.xsom.XSComponent;
  45 
  46 import org.xml.sax.Locator;
  47 
  48 /**
  49  * {@link ReferencePropertyInfo} for the compiler.
  50  *
  51  * @author Kohsuke Kawaguchi
  52  */
  53 public final class CReferencePropertyInfo extends CPropertyInfo implements ReferencePropertyInfo<NType,NClass> {
  54 
  55     /**
  56      * True if this property can never be absent legally.
  57      */
  58     private final boolean required;
  59 
  60     /**
  61      * List of referenced elements.
  62      */
  63     private final Set<CElement> elements = new HashSet<CElement>();
  64 
  65     private final boolean isMixed;
  66     private WildcardMode wildcard;
  67     private boolean dummy;
  68     private boolean content;
  69     private boolean isMixedExtendedCust = false;
  70 
  71     public CReferencePropertyInfo(String name, boolean collection, boolean required, boolean isMixed, XSComponent source,
  72                                   CCustomizations customizations, Locator locator, boolean dummy, boolean content, boolean isMixedExtended) {   // 'dummy' and 'content' here for NHIN fix - a hack in order to be able to handle extended mixed types better
  73         super(name, (collection||isMixed) && (!dummy), source, customizations, locator);
  74         this.isMixed = isMixed;
  75         this.required = required;
  76         this.dummy = dummy;
  77         this.content = content;
  78         this.isMixedExtendedCust = isMixedExtended;
  79     }
  80 
  81     public Set<? extends CTypeInfo> ref() {
  82 //        if(wildcard==null && !isMixed())
  83 //            return getElements();
  84 
  85         // ugly hack to get the signature right for substitution groups
  86         // when a class is generated for elements,they don't form a nice type hierarchy,
  87         // so the Java types of the substitution members need to be taken into account
  88         // when computing the signature
  89 
  90         final class RefList extends HashSet<CTypeInfo> {
  91             RefList() {
  92                 super(elements.size());
  93                 addAll(elements);
  94             }
  95             @Override
  96             public boolean addAll( Collection<? extends CTypeInfo> col ) {
  97                 boolean r = false;
  98                 for (CTypeInfo e : col) {
  99                     if(e instanceof CElementInfo) {
 100                         // UGLY. element substitution is implemented in a way that
 101                         // the derived elements are not assignable to base elements.
 102                         // so when we compute the signature, we have to take derived types
 103                         // into account
 104                         r |= addAll( ((CElementInfo)e).getSubstitutionMembers());
 105                     }
 106                     r |= add(e);
 107                 }
 108                 return r;
 109             }
 110         }
 111 
 112         RefList r = new RefList();
 113         if(wildcard!=null) {
 114             if(wildcard.allowDom)
 115                 r.add(CWildcardTypeInfo.INSTANCE);
 116             if(wildcard.allowTypedObject)
 117                 // we aren't really adding an AnyType.
 118                 // this is a kind of hack to generate Object as a signature
 119                 r.add(CBuiltinLeafInfo.ANYTYPE);
 120         }
 121         if(isMixed())
 122             r.add(CBuiltinLeafInfo.STRING);
 123 
 124         return r;
 125     }
 126 
 127     public Set<CElement> getElements() {
 128         return elements;
 129     }
 130 
 131     public boolean isMixed() {
 132         return isMixed;
 133     }
 134 
 135     public boolean isDummy() {
 136         return dummy;
 137     }
 138 
 139     public boolean isContent() {
 140         return content;
 141     }
 142 
 143     public boolean isMixedExtendedCust() {
 144         return isMixedExtendedCust;
 145     }
 146 
 147     /**
 148      * We'll never use a wrapper element in XJC. Always return null.
 149      */
 150     @Deprecated
 151     public QName getXmlName() {
 152         return null;
 153     }
 154 
 155     /**
 156      * Reference properties refer to elements, and none of the Java primitive type
 157      * maps to an element. Thus a reference property is always unboxable.
 158      */
 159     @Override
 160     public boolean isUnboxable() {
 161         return false;
 162     }
 163 
 164     // the same as above
 165     @Override
 166     public boolean isOptionalPrimitive() {
 167         return false;
 168     }
 169 
 170     public <V> V accept(CPropertyVisitor<V> visitor) {
 171         return visitor.onReference(this);
 172     }
 173 
 174     public CAdapter getAdapter() {
 175         return null;
 176     }
 177 
 178     public final PropertyKind kind() {
 179         return PropertyKind.REFERENCE;
 180     }
 181 
 182     /**
 183      * A reference property can never be ID/IDREF because they always point to
 184      * other element classes.
 185      */
 186     public ID id() {
 187         return ID.NONE;
 188     }
 189 
 190     public WildcardMode getWildcard() {
 191         return wildcard;
 192     }
 193 
 194     public void setWildcard(WildcardMode mode) {
 195         this.wildcard = mode;
 196     }
 197 
 198     public NClass getDOMHandler() {
 199         // TODO: support other DOM handlers
 200         if(getWildcard()!=null)
 201             return NavigatorImpl.create(W3CDomHandler.class);
 202         else
 203             return null;
 204     }
 205 
 206     public MimeType getExpectedMimeType() {
 207         return null;
 208     }
 209 
 210     public boolean isCollectionNillable() {
 211         // in XJC, we never recognize a nillable collection pattern, so this is always false.
 212         return false;
 213     }
 214 
 215     public boolean isCollectionRequired() {
 216         // in XJC, we never recognize a nillable collection pattern, so this is always false.
 217         return false;
 218     }
 219 
 220     // reference property cannot have a type.
 221     public QName getSchemaType() {
 222         return null;
 223     }
 224 
 225     public boolean isRequired() {
 226         return required;
 227     }
 228 
 229     @Override
 230     public QName collectElementNames(Map<QName, CPropertyInfo> table) {
 231         for (CElement e : elements) {
 232             QName n = e.getElementName();
 233             if(table.containsKey(n))
 234                 return n;
 235             table.put(n,this);
 236         }
 237         return null;
 238     }
 239 }