1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xerces.internal.impl.xs;
23
24import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo;
25import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
26import com.sun.org.apache.xerces.internal.xs.XSAnnotation;
27import com.sun.org.apache.xerces.internal.xs.XSAttributeGroupDefinition;
28import com.sun.org.apache.xerces.internal.xs.XSAttributeUse;
29import com.sun.org.apache.xerces.internal.xs.XSConstants;
30import com.sun.org.apache.xerces.internal.xs.XSNamespaceItem;
31import com.sun.org.apache.xerces.internal.xs.XSObjectList;
32import com.sun.org.apache.xerces.internal.xs.XSWildcard;
33
34/**
35 * The XML representation for an attribute group declaration
36 * schema component is a global <attributeGroup> element information item
37 *
38 * @xerces.internal
39 *
40 * @author Sandy Gao, IBM
41 * @author Rahul Srivastava, Sun Microsystems Inc.
42 *
43 */
44public class XSAttributeGroupDecl implements XSAttributeGroupDefinition {
45
46    // name of the attribute group
47    public String fName = null;
48    // target namespace of the attribute group
49    public String fTargetNamespace = null;
50    // number of attribute uses included by this attribute group
51    int fAttrUseNum = 0;
52    // attribute uses included by this attribute group
53    private static final int INITIAL_SIZE = 5;
54    XSAttributeUseImpl[] fAttributeUses = new XSAttributeUseImpl[INITIAL_SIZE];
55    // attribute wildcard included by this attribute group
56    public XSWildcardDecl fAttributeWC = null;
57    // whether there is an attribute use whose type is or is derived from ID.
58    public String fIDAttrName = null;
59
60    // optional annotation
61    public XSObjectList fAnnotations;
62
63    protected XSObjectListImpl fAttrUses = null;
64
65    // The namespace schema information item corresponding to the target namespace
66    // of the attribute group definition, if it is globally declared; or null otherwise.
67    private XSNamespaceItem fNamespaceItem = null;
68
69    // add an attribute use
70    // if the type is derived from ID, but there is already another attribute
71    // use of type ID, then return the name of the other attribute use;
72    // otherwise, return null
73    public String addAttributeUse(XSAttributeUseImpl attrUse) {
74
75        // if this attribute use is prohibited, then don't check whether it's
76        // of type ID
77        if (attrUse.fUse != SchemaSymbols.USE_PROHIBITED) {
78            if (attrUse.fAttrDecl.fType.isIDType()) {
79                // if there is already an attribute use of type ID,
80                // return its name (and don't add it to the list, to avoid
81                // interruption to instance validation.
82                if (fIDAttrName == null)
83                    fIDAttrName = attrUse.fAttrDecl.fName;
84                else
85                    return fIDAttrName;
86            }
87        }
88
89        if (fAttrUseNum == fAttributeUses.length) {
90            fAttributeUses = resize(fAttributeUses, fAttrUseNum*2);
91        }
92        fAttributeUses[fAttrUseNum++] = attrUse;
93
94        return null;
95    }
96
97    public void replaceAttributeUse(XSAttributeUse oldUse, XSAttributeUseImpl newUse) {
98        for (int i=0; i<fAttrUseNum; i++) {
99            if (fAttributeUses[i] == oldUse) {
100                fAttributeUses[i] = newUse;
101            }
102        }
103    }
104
105    public XSAttributeUse getAttributeUse(String namespace, String name) {
106        for (int i=0; i<fAttrUseNum; i++) {
107            if ( (fAttributeUses[i].fAttrDecl.fTargetNamespace == namespace) &&
108                 (fAttributeUses[i].fAttrDecl.fName == name) )
109                return fAttributeUses[i];
110        }
111
112        return null;
113    }
114
115    public XSAttributeUse getAttributeUseNoProhibited(String namespace, String name) {
116        for (int i=0; i<fAttrUseNum; i++) {
117            if ( (fAttributeUses[i].fAttrDecl.fTargetNamespace == namespace) &&
118                 (fAttributeUses[i].fAttrDecl.fName == name) &&
119                 (fAttributeUses[i].fUse != SchemaSymbols.USE_PROHIBITED))
120                return fAttributeUses[i];
121        }
122
123        return null;
124    }
125
126    public void removeProhibitedAttrs() {
127        if (fAttrUseNum == 0) return;
128        // Remove all prohibited attributes.
129        int count = 0;
130        XSAttributeUseImpl[] uses = new XSAttributeUseImpl[fAttrUseNum];
131        for (int i = 0; i < fAttrUseNum; i++) {
132            if (fAttributeUses[i].fUse != SchemaSymbols.USE_PROHIBITED) {
133                uses[count++] = fAttributeUses[i];
134            }
135        }
136        fAttributeUses = uses;
137        fAttrUseNum = count;
138
139        // Do not remove attributes that have the same name as the prohibited
140        // ones, because they are specified at the same level. Prohibited
141        // attributes are only to remove attributes from the base type in a
142        // restriction.
143//        int newCount = 0;
144//        if (pCount > 0) {
145//            OUTER: for (int i = 0; i < fAttrUseNum; i++) {
146//                if (fAttributeUses[i].fUse == SchemaSymbols.USE_PROHIBITED)
147//                    continue;
148//                for (int j = 1; j <= pCount; j++) {
149//                    if (fAttributeUses[i].fAttrDecl.fName == pUses[fAttrUseNum-pCount].fAttrDecl.fName &&
150//                        fAttributeUses[i].fAttrDecl.fTargetNamespace == pUses[fAttrUseNum-pCount].fAttrDecl.fTargetNamespace) {
151//                        continue OUTER;
152//                    }
153//                }
154//                pUses[newCount++] = fAttributeUses[i];
155//            }
156//            fAttributeUses = pUses;
157//            fAttrUseNum = newCount;
158//        }
159    }
160
161    /**
162     * Check that the attributes in this group validly restrict those from a base group.
163     * If an error is found, an Object[] is returned. This contains the arguments for the error message
164     * describing the error. The last element in the array (at index arr.length - 1) is the the error code.
165     * Returns null if there is no error.
166     *
167     * REVISIT: is there a better way of returning the appropriate information for the error?
168     *
169     * @param typeName the name of the type containing this attribute group, used for error reporting purposes
170     * @param baseGroup the XSAttributeGroupDecl that is the base we are checking against
171     */
172    public Object[] validRestrictionOf(String typeName, XSAttributeGroupDecl baseGroup) {
173
174        Object[] errorArgs = null;
175        XSAttributeUseImpl attrUse = null;
176        XSAttributeDecl attrDecl = null;
177        XSAttributeUseImpl baseAttrUse = null;
178        XSAttributeDecl baseAttrDecl = null;
179
180        for (int i=0; i<fAttrUseNum; i++) {
181
182            attrUse = fAttributeUses[i];
183            attrDecl = attrUse.fAttrDecl;
184
185            // Look for a match in the base
186            baseAttrUse = (XSAttributeUseImpl)baseGroup.getAttributeUse(attrDecl.fTargetNamespace,attrDecl.fName);
187            if (baseAttrUse != null) {
188                //
189                // derivation-ok-restriction.  Constraint 2.1.1
190                //
191
192                if (baseAttrUse.getRequired() && !attrUse.getRequired()) {
193                    errorArgs = new Object[]{typeName, attrDecl.fName,
194                                             attrUse.fUse == SchemaSymbols.USE_OPTIONAL ? SchemaSymbols.ATTVAL_OPTIONAL : SchemaSymbols.ATTVAL_PROHIBITED,
195                                             "derivation-ok-restriction.2.1.1"};
196                    return errorArgs;
197                }
198
199                // if this attribute is prohibited in the derived type, don't
200                // need to check any of the following constraints.
201                if (attrUse.fUse == SchemaSymbols.USE_PROHIBITED) {
202                    continue;
203                }
204
205                baseAttrDecl = baseAttrUse.fAttrDecl;
206                //
207                // derivation-ok-restriction.  Constraint 2.1.1
208                //
209                if (! XSConstraints.checkSimpleDerivationOk(attrDecl.fType,
210                                                            baseAttrDecl.fType,
211                                                            baseAttrDecl.fType.getFinal()) ) {
212                                        errorArgs = new Object[]{typeName, attrDecl.fName, attrDecl.fType.getName(),
213                                                                     baseAttrDecl.fType.getName(), "derivation-ok-restriction.2.1.2"};
214                                        return errorArgs;
215                }
216
217
218                //
219                // derivation-ok-restriction.  Constraint 2.1.3
220                //
221                int baseConsType=baseAttrUse.fConstraintType!=XSConstants.VC_NONE?
222                                 baseAttrUse.fConstraintType:baseAttrDecl.getConstraintType();
223                int thisConstType = attrUse.fConstraintType!=XSConstants.VC_NONE?
224                                    attrUse.fConstraintType:attrDecl.getConstraintType();
225
226                if (baseConsType == XSConstants.VC_FIXED) {
227
228                    if (thisConstType != XSConstants.VC_FIXED) {
229                                                errorArgs = new Object[]{typeName, attrDecl.fName,
230                                                                                                 "derivation-ok-restriction.2.1.3.a"};
231                                                return errorArgs;
232                    } else {
233                        // check the values are the same.
234                        ValidatedInfo baseFixedValue=(baseAttrUse.fDefault!=null ?
235                                                      baseAttrUse.fDefault: baseAttrDecl.fDefault);
236                        ValidatedInfo thisFixedValue=(attrUse.fDefault!=null ?
237                                                      attrUse.fDefault: attrDecl.fDefault);
238                        if (!baseFixedValue.actualValue.equals(thisFixedValue.actualValue)) {
239                                                        errorArgs = new Object[]{typeName, attrDecl.fName, thisFixedValue.stringValue(),
240                                                                                                         baseFixedValue.stringValue(), "derivation-ok-restriction.2.1.3.b"};
241                                                        return errorArgs;
242                        }
243
244                    }
245
246                }
247            } else {
248                // No matching attribute in base - there should be a matching wildcard
249
250                //
251                // derivation-ok-restriction.  Constraint 2.2
252                //
253                if (baseGroup.fAttributeWC == null) {
254                                        errorArgs = new Object[]{typeName, attrDecl.fName,
255                                                                                         "derivation-ok-restriction.2.2.a"};
256                                        return errorArgs;
257                }
258                else if (!baseGroup.fAttributeWC.allowNamespace(attrDecl.fTargetNamespace)) {
259                                        errorArgs = new Object[]{typeName, attrDecl.fName,
260                                             attrDecl.fTargetNamespace==null?"":attrDecl.fTargetNamespace,
261                                                                                         "derivation-ok-restriction.2.2.b"};
262                                        return errorArgs;
263                }
264            }
265        }
266
267        //
268        // Check that any REQUIRED attributes in the base have matching attributes
269        // in this group
270        // derivation-ok-restriction.  Constraint 3
271        //
272        for (int i=0; i<baseGroup.fAttrUseNum; i++) {
273
274            baseAttrUse = baseGroup.fAttributeUses[i];
275
276            if (baseAttrUse.fUse == SchemaSymbols.USE_REQUIRED) {
277
278                baseAttrDecl = baseAttrUse.fAttrDecl;
279                // Look for a match in this group
280                if (getAttributeUse(baseAttrDecl.fTargetNamespace,baseAttrDecl.fName) == null) {
281                                        errorArgs = new Object[]{typeName, baseAttrUse.fAttrDecl.fName,
282                                                                                         "derivation-ok-restriction.3"};
283                                        return errorArgs;
284                }
285            }
286        }
287
288
289        // Now, check wildcards
290        //
291        // derivation-ok-restriction.  Constraint 4
292        //
293        if (fAttributeWC != null) {
294            if (baseGroup.fAttributeWC == null) {
295                                errorArgs = new Object[]{typeName, "derivation-ok-restriction.4.1"};
296                                return errorArgs;
297            }
298            if (! fAttributeWC.isSubsetOf(baseGroup.fAttributeWC)) {
299                                errorArgs = new Object[]{typeName, "derivation-ok-restriction.4.2"};
300                                return errorArgs;
301            }
302            if (fAttributeWC.weakerProcessContents(baseGroup.fAttributeWC)) {
303                                errorArgs = new Object[]{typeName,
304                                                                                 fAttributeWC.getProcessContentsAsString(),
305                                                                                 baseGroup.fAttributeWC.getProcessContentsAsString(),
306                                                                                 "derivation-ok-restriction.4.3"};
307                                return errorArgs;
308            }
309        }
310
311        return null;
312
313    }
314
315    static final XSAttributeUseImpl[] resize(XSAttributeUseImpl[] oldArray, int newSize) {
316        XSAttributeUseImpl[] newArray = new XSAttributeUseImpl[newSize];
317        System.arraycopy(oldArray, 0, newArray, 0, Math.min(oldArray.length, newSize));
318        return newArray;
319    }
320
321    // reset the attribute group declaration
322    public void reset(){
323        fName = null;
324        fTargetNamespace = null;
325        // reset attribute uses
326        for (int i=0;i<fAttrUseNum;i++) {
327            fAttributeUses[i] = null;
328        }
329        fAttrUseNum = 0;
330        fAttributeWC = null;
331        fAnnotations = null;
332        fIDAttrName = null;
333
334    }
335
336    /**
337     * Get the type of the object, i.e ELEMENT_DECLARATION.
338     */
339    public short getType() {
340        return XSConstants.ATTRIBUTE_GROUP;
341    }
342
343    /**
344     * The <code>name</code> of this <code>XSObject</code> depending on the
345     * <code>XSObject</code> type.
346     */
347    public String getName() {
348        return fName;
349    }
350
351    /**
352     * The namespace URI of this node, or <code>null</code> if it is
353     * unspecified.  defines how a namespace URI is attached to schema
354     * components.
355     */
356    public String getNamespace() {
357        return fTargetNamespace;
358    }
359
360    /**
361     * {attribute uses} A set of attribute uses.
362     */
363    public XSObjectList getAttributeUses() {
364        if (fAttrUses == null){
365            fAttrUses = new XSObjectListImpl(fAttributeUses, fAttrUseNum);
366        }
367        return fAttrUses;
368    }
369
370    /**
371     * {attribute wildcard} Optional. A wildcard.
372     */
373    public XSWildcard getAttributeWildcard() {
374        return fAttributeWC;
375    }
376
377    /**
378     * Optional. Annotation.
379     */
380    public XSAnnotation getAnnotation() {
381        return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null;
382    }
383
384    /**
385     * Optional. Annotations.
386     */
387    public XSObjectList getAnnotations() {
388        return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST;
389    }
390
391    /**
392     * @see org.apache.xerces.xs.XSObject#getNamespaceItem()
393     */
394    public XSNamespaceItem getNamespaceItem() {
395        return fNamespaceItem;
396    }
397
398    void setNamespaceItem(XSNamespaceItem namespaceItem) {
399        fNamespaceItem = namespaceItem;
400    }
401
402} // class XSAttributeGroupDecl
403