1/*
2 * Copyright (c) 1997, 2014, 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
26package com.sun.tools.internal.xjc.model;
27
28import java.util.Collection;
29import java.util.LinkedHashSet;
30import java.util.Set;
31import java.util.Map;
32
33import javax.activation.MimeType;
34import javax.xml.bind.annotation.W3CDomHandler;
35import javax.xml.namespace.QName;
36
37import com.sun.tools.internal.xjc.model.nav.NClass;
38import com.sun.tools.internal.xjc.model.nav.NType;
39import com.sun.tools.internal.xjc.model.nav.NavigatorImpl;
40import com.sun.xml.internal.bind.v2.model.core.ID;
41import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
42import com.sun.xml.internal.bind.v2.model.core.ReferencePropertyInfo;
43import com.sun.xml.internal.bind.v2.model.core.WildcardMode;
44import com.sun.xml.internal.xsom.XSComponent;
45
46import org.xml.sax.Locator;
47
48/**
49 * {@link ReferencePropertyInfo} for the compiler.
50 *
51 * @author Kohsuke Kawaguchi
52 */
53public 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 LinkedHashSet<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 LinkedHashSet<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    @Override
175    public <R, P> R accept(CPropertyVisitor2<R, P> visitor, P p) {
176        return visitor.visit(this, p);
177    }
178
179    public CAdapter getAdapter() {
180        return null;
181    }
182
183    public final PropertyKind kind() {
184        return PropertyKind.REFERENCE;
185    }
186
187    /**
188     * A reference property can never be ID/IDREF because they always point to
189     * other element classes.
190     */
191    public ID id() {
192        return ID.NONE;
193    }
194
195    public WildcardMode getWildcard() {
196        return wildcard;
197    }
198
199    public void setWildcard(WildcardMode mode) {
200        this.wildcard = mode;
201    }
202
203    public NClass getDOMHandler() {
204        // TODO: support other DOM handlers
205        if(getWildcard()!=null)
206            return NavigatorImpl.create(W3CDomHandler.class);
207        else
208            return null;
209    }
210
211    public MimeType getExpectedMimeType() {
212        return null;
213    }
214
215    public boolean isCollectionNillable() {
216        // in XJC, we never recognize a nillable collection pattern, so this is always false.
217        return false;
218    }
219
220    public boolean isCollectionRequired() {
221        // in XJC, we never recognize a nillable collection pattern, so this is always false.
222        return false;
223    }
224
225    // reference property cannot have a type.
226    public QName getSchemaType() {
227        return null;
228    }
229
230    public boolean isRequired() {
231        return required;
232    }
233
234    @Override
235    public QName collectElementNames(Map<QName, CPropertyInfo> table) {
236        for (CElement e : elements) {
237            QName n = e.getElementName();
238            if(table.containsKey(n))
239                return n;
240            table.put(n,this);
241        }
242        return null;
243    }
244}
245