blob: 408f96105bea4a63ea1367c049e3b6571b594f8b [file] [log] [blame]
/*
* 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.netbeans.modules.xml.schema.model.impl;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.netbeans.modules.xml.schema.model.Annotation;
import org.netbeans.modules.xml.xam.Component;
import org.netbeans.modules.xml.xam.locator.CatalogModelException;
import org.netbeans.modules.xml.schema.model.GlobalType;
import org.netbeans.modules.xml.schema.model.Notation;
import org.netbeans.modules.xml.schema.model.SchemaComponent;
import org.netbeans.modules.xml.schema.model.Form;
import org.netbeans.modules.xml.schema.model.GlobalAttribute;
import org.netbeans.modules.xml.schema.model.GlobalAttributeGroup;
import org.netbeans.modules.xml.schema.model.GlobalComplexType;
import org.netbeans.modules.xml.schema.model.GlobalElement;
import org.netbeans.modules.xml.schema.model.GlobalSimpleType;
import org.netbeans.modules.xml.schema.model.GlobalGroup;
import org.netbeans.modules.xml.schema.model.Import;
import org.netbeans.modules.xml.schema.model.Include;
import org.netbeans.modules.xml.schema.model.Redefine;
import org.netbeans.modules.xml.schema.model.Schema;
import org.netbeans.modules.xml.schema.model.Schema.Block;
import org.netbeans.modules.xml.schema.model.Schema.Final;
import org.netbeans.modules.xml.schema.model.SchemaModel;
import org.netbeans.modules.xml.schema.model.SchemaModelReference;
import org.netbeans.modules.xml.schema.model.visitor.SchemaVisitor;
import org.w3c.dom.Element;
/**
* @author Vidhya Narayanan
* @author Nam Nguyen
*/
public class SchemaImpl extends SchemaComponentImpl implements Schema {
public static final String TNS = "tns"; //NOI18N
private Component foreignParent;
private CachedTargetNamespace mCachedTargetNamespace =
new CachedTargetNamespace(this);
/** Creates a new instance of SchemaImpl */
public SchemaImpl(SchemaModelImpl model) {
this(model, createNewComponent(SchemaElements.SCHEMA, model));
}
public SchemaImpl(SchemaModelImpl model, Element e){
super(model,e);
}
/**
*
*
*/
public Class<? extends SchemaComponent> getComponentType() {
return Schema.class;
}
public Collection<SchemaModelReference> getSchemaReferences() {
return getChildren(SchemaModelReference.class);
}
/**
* Visitor providing
*/
public void accept(SchemaVisitor visitor) {
visitor.visit(this);
}
public Collection<GlobalElement> getElements() {
return getChildren(GlobalElement.class);
}
public void removeElement(GlobalElement element) {
removeChild(ELEMENTS_PROPERTY, element);
}
public void addElement(GlobalElement element) {
appendChild(ELEMENTS_PROPERTY, element);
}
public Collection<GlobalAttributeGroup> getAttributeGroups() {
return getChildren(GlobalAttributeGroup.class);
}
public void removeAttributeGroup(GlobalAttributeGroup group) {
removeChild(ATTRIBUTE_GROUPS_PROPERTY, group);
}
public void addAttributeGroup(GlobalAttributeGroup group) {
appendChild(ATTRIBUTE_GROUPS_PROPERTY, group);
}
public void removeExternalReference(SchemaModelReference ref) {
removeChild(SCHEMA_REFERENCES_PROPERTY, ref);
}
public void addExternalReference(SchemaModelReference ref) {
List<Class<? extends SchemaComponent>> afterList = new ArrayList<Class<? extends SchemaComponent>>();
afterList.add(Annotation.class);
afterList.add(SchemaModelReference.class);
addAfter(SCHEMA_REFERENCES_PROPERTY, ref, afterList);
}
public Collection<GlobalComplexType> getComplexTypes() {
return getChildren(GlobalComplexType.class);
}
public void removeComplexType(GlobalComplexType type) {
removeChild(COMPLEX_TYPES_PROPERTY, type);
}
public void addComplexType(GlobalComplexType type) {
appendChild(COMPLEX_TYPES_PROPERTY, type);
}
public Collection<GlobalAttribute> getAttributes() {
return getChildren(GlobalAttribute.class);
}
public void addAttribute(GlobalAttribute attr) {
appendChild(ATTRIBUTES_PROPERTY, attr);
}
public void removeAttribute(GlobalAttribute attr) {
removeChild(ATTRIBUTES_PROPERTY, attr);
}
public void setVersion(String ver) {
setAttribute(VERSION_PROPERTY, SchemaAttributes.VERSION, ver);
}
public String getVersion() {
return getAttribute(SchemaAttributes.VERSION);
}
public void setLanguage(String language) {
setAttribute(LANGUAGE_PROPERTY, SchemaAttributes.LANGUAGE, language);
}
public String getLanguage() {
return getAttribute(SchemaAttributes.LANGUAGE);
}
public void setFinalDefault(Set<Final> finalDefault) {
setAttribute(FINAL_DEFAULT_PROPERTY, SchemaAttributes.FINAL_DEFAULT,
finalDefault == null ? null :
Util.convertEnumSet(Final.class, finalDefault));
}
public Set<Final> getFinalDefault() {
String s = getAttribute(SchemaAttributes.FINAL_DEFAULT);
return s == null ? null : Util.valuesOf(Final.class, s);
}
public Set<Final> getFinalDefaultEffective() {
Set<Final> v = getFinalDefault();
return v == null ? getFinalDefaultDefault() : v;
}
public Set<Final> getFinalDefaultDefault() {
return new DerivationsImpl.DerivationSet<Final>();
}
public void setTargetNamespace(String uri) {
String currentTargetNamespace = getTargetNamespace();
setAttribute(TARGET_NAMESPACE_PROPERTY, SchemaAttributes.TARGET_NS, uri);
ensureValueNamespaceDeclared(uri, currentTargetNamespace, TNS);
}
public String getTargetNamespace() {
return mCachedTargetNamespace.getTargetNamespace();
}
public void setElementFormDefault(Form form) {
setAttribute(ELEMENT_FORM_DEFAULT_PROPERTY, SchemaAttributes.ELEM_FORM_DEFAULT, form);
}
public Form getElementFormDefault() {
String s = getAttribute(SchemaAttributes.ELEM_FORM_DEFAULT);
return s == null ? null : Util.parse(Form.class, s);
}
public void setAttributeFormDefault(Form form) {
setAttribute(ATTRIBUTE_FORM_DEFAULT_PROPERTY, SchemaAttributes.ATTR_FORM_DEFAULT, form);
}
public Form getAttributeFormDefault() {
String s = getAttribute(SchemaAttributes.ATTR_FORM_DEFAULT);
return s == null ? null : Util.parse(Form.class, s);
}
public Collection<GlobalSimpleType> getSimpleTypes() {
return getChildren(GlobalSimpleType.class);
}
public void removeSimpleType(GlobalSimpleType type) {
removeChild(SIMPLE_TYPES_PROPERTY, type);
}
public void addSimpleType(GlobalSimpleType type) {
appendChild(SIMPLE_TYPES_PROPERTY, type);
}
public Collection<GlobalGroup> getGroups() {
return getChildren(GlobalGroup.class);
}
public void removeGroup(GlobalGroup group) {
removeChild(GROUPS_PROPERTY, group);
}
public void addGroup(GlobalGroup group) {
appendChild(GROUPS_PROPERTY, group);
}
public Collection<Notation> getNotations() {
return getChildren(Notation.class);
}
public void removeNotation(Notation notation) {
removeChild(NOTATIONS_PROPERTY, notation);
}
public void addNotation(Notation notation) {
appendChild(NOTATIONS_PROPERTY, notation);
}
public void setBlockDefault(Set<Block> blockDefault) {
setAttribute(BLOCK_DEFAULT_PROPERTY, SchemaAttributes.BLOCK_DEFAULT,
blockDefault == null ? null :
Util.convertEnumSet(Block.class, blockDefault));
}
public Set<Block> getBlockDefault() {
String s = getAttribute(SchemaAttributes.BLOCK_DEFAULT);
return s == null ? null : Util.valuesOf(Block.class, s);
}
public Set<Block> getBlockDefaultEffective() {
Set<Block> v = getBlockDefault();
return v == null ? getBlockDefaultDefault() : v;
}
public Set<Block> getBlockDefaultDefault() {
return new DerivationsImpl.DerivationSet<Block>();
}
public Form getElementFormDefaultEffective() {
Form v = getElementFormDefault();
return v == null ? getElementFormDefaultDefault() : v;
}
public Form getElementFormDefaultDefault() {
return Form.UNQUALIFIED;
}
public Form getAttributeFormDefaultEffective() {
Form v = getAttributeFormDefault();
return v == null ? getAttributeFormDefaultDefault() : v;
}
public Form getAttributeFormDefaultDefault() {
return Form.UNQUALIFIED;
}
public Collection<Redefine> getRedefines() {
return getChildren(Redefine.class);
}
public Collection<Include> getIncludes() {
return getChildren(Include.class);
}
public Collection<Import> getImports() {
return getChildren(Import.class);
}
public Collection<GlobalElement> findAllGlobalElements() {
Collection<GlobalElement> result = new ArrayList<GlobalElement>();
Collection<GlobalElement> tempCollection = this.getElements();
if(tempCollection != null) {
result.addAll(tempCollection);
}
// TODO need to add redefined elements to search
result.addAll(getExternalGlobalElements(getImports()));
result.addAll(getExternalGlobalElements(getIncludes()));
result.addAll(getExternalGlobalElements(getRedefines()));
return result;
}
private Collection<GlobalElement> getExternalGlobalElements(
Collection<? extends SchemaModelReference> externalRefs){
Collection<GlobalElement> result = new ArrayList<GlobalElement>();
for(SchemaModelReference smr : externalRefs) {
try {
SchemaModel sm = smr.resolveReferencedModel();
if (sm.getState().equals(SchemaModel.State.VALID)) {
result.addAll(sm.getSchema().findAllGlobalElements());
}
} catch (CatalogModelException ex) {
// we are swalling this exception as the model cannot be found
// we still want to continue to try and find the reference though
}
}
return result;
}
public Collection<GlobalType> findAllGlobalTypes() {
Collection<GlobalType> result = new ArrayList<GlobalType>();
//add all SimpleTypes
Collection<? extends GlobalType> tempCollection = this.getSimpleTypes();
if(tempCollection != null)
result.addAll(tempCollection);
//add all complex types
tempCollection = this.getComplexTypes();
if(tempCollection != null)
result.addAll(tempCollection);
//add from all the referenced docs
result.addAll(getExternalGlobalTypes(getImports()));
result.addAll(getExternalGlobalTypes(getIncludes()));
result.addAll(getExternalGlobalTypes(getRedefines()));
return result;
}
private Collection<GlobalType> getExternalGlobalTypes(
Collection<? extends SchemaModelReference> externalRefs){
Collection<GlobalType> result = new ArrayList<GlobalType>();
for(SchemaModelReference smr : externalRefs){
try {
SchemaModel sm = smr.resolveReferencedModel();
if (sm.getState().equals(SchemaModel.State.VALID)) {
result.addAll(sm.getSchema().findAllGlobalTypes());
}
} catch (CatalogModelException ex) {
// swallow this exception to allow some resolution to occur
}
}
return result;
}
public Component getForeignParent() {
return foreignParent;
}
public void setForeignParent(Component component) {
foreignParent = component;
}
/**
* Helps to improve performance because the targetNamespace is asked too frequently.
* See the issue #169435
*/
private static class CachedTargetNamespace {
// deliberately using new String, to prevent sharing
private static final String NO_NAMESPACE_PLACEHOLDER = new String("<null>");
private final Schema mSchema;
private volatile String mTargetNamespace = null;
public CachedTargetNamespace(Schema schema) {
mSchema = schema;
//
SchemaModel sModel = mSchema.getModel();
assert sModel != null;
sModel.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (Schema.TARGET_NAMESPACE_PROPERTY.equals(propName)) {
// The TNS has to be repopulated
discardCache();
}
}
});
}
public synchronized void discardCache() {
mTargetNamespace = null;
}
private static String translateNamespace(String s) {
// == comparison is deliberate
return s == NO_NAMESPACE_PLACEHOLDER ? null : s;
}
public String getTargetNamespace() {
String ns = mTargetNamespace;
boolean inTransaction = mSchema.getModel().isIntransaction();
if (ns != null && !inTransaction) {
return translateNamespace(ns);
}
//
// Use ordinary way if the model in transaction because
// the cached value remains unchanged before transaction is commited.
// TODO sdedic: not sure about the above comment. The original code changed the cached
// value if model was inTransaction(). I retain the behaviour, but it seems to contradict the comment.
String tns = mSchema.getAttribute(SchemaAttributes.TARGET_NS);
if (tns == null) {
mTargetNamespace = NO_NAMESPACE_PLACEHOLDER;
} else {
mTargetNamespace = tns;
}
return tns;
}
}
}