
org.glassfish.hk2.xml.internal.ModelImpl Maven / Gradle / Ivy
/*
* Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.hk2.xml.internal;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import javax.xml.namespace.QName;
import org.glassfish.hk2.utilities.general.GeneralUtilities;
import org.glassfish.hk2.utilities.reflection.ClassReflectionHelper;
import org.glassfish.hk2.utilities.reflection.MethodWrapper;
import org.glassfish.hk2.xml.internal.alt.AltMethod;
import org.glassfish.hk2.xml.internal.alt.clazz.MethodAltMethodImpl;
import org.glassfish.hk2.xml.spi.Model;
/**
* This model is a description of the children and non-children nodes
* of a Bean. It contains only Strings or other easy to constructs
* structures so that it can be added to the proxy at build time
* and hence save some reflection at runtime
*
* @author jwells
*
*/
public class ModelImpl implements Model {
private static final long serialVersionUID = 752816761552710497L;
private final ReentrantLock lock = new ReentrantLock();
/** For thread safety on the computed fields */
// This is probably wrong, no need for static lock
private final static ReentrantLock slock = new ReentrantLock();
/** The interface from which the JAXB proxy was created, fully qualified */
private String originalInterface;
/** Calculated at runtime lazily this is the original interface as a class */
private volatile Class> originalInterfaceAsClass;
/** The JAXB proxy of the originalInterface, fully qualified */
private String translatedClass;
/** Calculated at runtime lazily this is the proxy as a class */
private volatile Class> translatedClassAsClass;
/** If this node can be a root, the xml tag of the root of the document */
private QName rootName;
/** A map from the xml tag to the parented child node */
private final Map childrenByName = new LinkedHashMap();
/** A map from xml tag to information about the non-child property */
private final Map nonChildProperty = new LinkedHashMap();
/** A map from xml tag to child data, ordered */
private final Map allChildren = new LinkedHashMap();
/** If this node has a key, this is the property name of the key */
private QName keyProperty;
/**
* These are calculated values and only filled in when asked for
*/
private Set unKeyedChildren = null;
private Set keyedChildren = null;
private transient JAUtilities jaUtilities = null;
private ClassLoader myLoader;
private Map keyToJavaNameMap = null;
private Set allXmlWrappers;
private String valuePropertyNamespace;
private String valueProperty;
private ChildDataModel valueData;
public ModelImpl() {
}
public ModelImpl(String originalInterface,
String translatedClass) {
this.originalInterface = originalInterface;
this.translatedClass = translatedClass;
}
public void setRootName(QName root) {
this.rootName = root;
}
public void setRootName(String rootNamespace, String rootName) {
this.rootName = QNameUtilities.createQName(rootNamespace, rootName);
}
public void setKeyProperty(QName qName) {
String namespace = QNameUtilities.getNamespace(qName);
String name = qName.getLocalPart();
setKeyProperty(namespace, name);
}
public void setKeyProperty(String keyNamespace, String keyProperty) {
this.keyProperty = QNameUtilities.createQName(keyNamespace, keyProperty);
}
public void addChild(
String childInterface,
String namespace,
String xmlTag,
String xmlAlias,
ChildType childType,
String givenDefault,
AliasType aliased,
String childWrapperTag,
String adapter,
boolean required,
String originalMethodName) {
ParentedModel pm = new ParentedModel(childInterface,
namespace,
xmlTag,
xmlAlias,
childType,
givenDefault,
aliased,
childWrapperTag,
adapter,
required,
originalMethodName);
childrenByName.put(QNameUtilities.createQName(namespace, xmlTag), pm);
allChildren.put(QNameUtilities.createQName(namespace, xmlTag), new ChildDescriptor(pm));
}
public void addNonChild(
QName qName,
String defaultValue,
String childType,
String childListType,
boolean isReference,
Format format,
AliasType aliasType,
String aliasOf,
boolean required,
String originalMethodName) {
String namespace = QNameUtilities.getNamespace(qName);
String xmlTag = qName.getLocalPart();
addNonChild(namespace,
xmlTag,
defaultValue,
childType,
childListType,
isReference,
format,
aliasType,
aliasOf,
required,
originalMethodName);
}
public void addNonChild(
String namespace,
String xmlTag,
String defaultValue,
String childType,
String childListType,
boolean isReference,
Format format,
AliasType aliasType,
String aliasOf,
boolean required,
String originalMethodName) {
ChildDataModel cdm = new ChildDataModel(childType,
childListType,
defaultValue,
isReference,
format,
aliasType,
aliasOf,
required,
originalMethodName);
nonChildProperty.put(QNameUtilities.createQName(namespace, xmlTag), cdm);
allChildren.put(QNameUtilities.createQName(namespace, xmlTag), new ChildDescriptor(cdm));
if (Format.VALUE.equals(format)) {
valuePropertyNamespace = namespace;
valueProperty = xmlTag;
valueData = cdm;
}
}
/**
* @return the originalInterface
*/
@Override
public String getOriginalInterface() {
return originalInterface;
}
/**
* @return the translatedClass
*/
@Override
public String getTranslatedClass() {
return translatedClass;
}
/**
* @return the rootName
*/
@Override
public QName getRootName() {
return rootName;
}
/**
* @return the keyProperty
*/
@Override
public QName getKeyProperty() {
return keyProperty;
}
public Map getChildrenByName() {
return childrenByName;
}
public Map getNonChildProperties() {
return nonChildProperty;
}
public Map getAllChildrenDescriptors() {
return allChildren;
}
public String getValuePropertyNamespace() {
return valuePropertyNamespace;
}
public String getValueProperty() {
return valueProperty;
}
public ChildDataModel getValueData() {
return valueData;
}
public Set getAllXmlWrappers() {
slock.lock();
try {
if (allXmlWrappers != null) return allXmlWrappers;
allXmlWrappers = new LinkedHashSet();
for (ParentedModel pm : childrenByName.values()) {
if (pm.getXmlWrapperTag() != null) {
allXmlWrappers.add(pm.getXmlWrapperTag());
}
}
return allXmlWrappers;
} finally {
slock.unlock();
}
}
public ChildDescriptor getChildDescriptor(QName xmlTag) {
return allChildren.get(xmlTag);
}
public Set getUnKeyedChildren() {
slock.lock();
try {
if (unKeyedChildren != null) return unKeyedChildren;
unKeyedChildren = new HashSet();
for (Map.Entry entry : childrenByName.entrySet()) {
if (entry.getValue().getChildModel().getKeyProperty() != null) continue;
unKeyedChildren.add(entry.getKey());
}
return unKeyedChildren;
} finally {
slock.unlock();
}
}
public Set getKeyedChildren() {
slock.lock();
try {
if (keyedChildren != null) return keyedChildren;
keyedChildren = new HashSet();
for (Map.Entry entry : childrenByName.entrySet()) {
if (entry.getValue().getChildModel().getKeyProperty() == null) continue;
keyedChildren.add(entry.getKey());
}
return keyedChildren;
} finally {
slock.unlock();
}
}
public void setJAUtilities(JAUtilities jaUtilities, ClassLoader myLoader) {
slock.lock();
try {
if (this.jaUtilities != null) return;
this.jaUtilities = jaUtilities;
this.myLoader = myLoader;
for (ParentedModel pm : childrenByName.values()) {
pm.setRuntimeInformation(jaUtilities, myLoader);
}
for (ChildDataModel cdm : nonChildProperty.values()) {
cdm.setLoader(myLoader);
}
} finally {
slock.unlock();
}
}
public String getDefaultChildValue(String propNamespace, String propName) {
QName propQName = QNameUtilities.createQName(propNamespace, propName);
slock.lock();
try {
ChildDataModel cd = nonChildProperty.get(propQName);
if (cd == null) return null;
return cd.getDefaultAsString();
} finally {
slock.unlock();
}
}
public ModelPropertyType getModelPropertyType(String propNamespace, String propName) {
QName propQName = QNameUtilities.createQName(propNamespace, propName);
slock.lock();
try {
if (nonChildProperty.containsKey(propQName)) return ModelPropertyType.FLAT_PROPERTY;
if (childrenByName.containsKey(propQName)) return ModelPropertyType.TREE_ROOT;
return ModelPropertyType.UNKNOWN;
} finally {
slock.unlock();
}
}
public Class> getNonChildType(String propNamespace, String propName) {
QName propQName = QNameUtilities.createQName(propNamespace, propName);
slock.lock();
try {
ChildDataModel cd = nonChildProperty.get(propQName);
if (cd == null) return null;
return cd.getChildTypeAsClass();
} finally {
slock.unlock();
}
}
public ParentedModel getChild(String propNamespace, String propName) {
QName propQName = QNameUtilities.createQName(propNamespace, propName);
slock.lock();
try {
return childrenByName.get(propQName);
} finally {
slock.unlock();
}
}
@Override
public Class> getOriginalInterfaceAsClass() {
if (originalInterfaceAsClass != null) return originalInterfaceAsClass;
slock.lock();
try {
if (originalInterfaceAsClass != null) return originalInterfaceAsClass;
originalInterfaceAsClass = GeneralUtilities.loadClass(myLoader, originalInterface);
return originalInterfaceAsClass;
} finally {
slock.unlock();
}
}
@Override
public Class> getProxyAsClass() {
if (translatedClassAsClass != null) return translatedClassAsClass;
slock.lock();
try {
if (translatedClassAsClass != null) return translatedClassAsClass;
translatedClassAsClass = GeneralUtilities.loadClass(myLoader, translatedClass);
return translatedClassAsClass;
} finally {
slock.unlock();
}
}
public Collection getAllChildren() {
slock.lock();
try {
return Collections.unmodifiableCollection(childrenByName.values());
} finally {
slock.unlock();
}
}
public Map getChildrenProperties() {
slock.lock();
try {
return Collections.unmodifiableMap(childrenByName);
} finally {
slock.unlock();
}
}
public Map getAllAttributeChildren() {
Map retVal = new LinkedHashMap();
for (Map.Entry candidate : nonChildProperty.entrySet()) {
QName xmlKey = candidate.getKey();
ChildDataModel childDataModel = candidate.getValue();
if (!Format.ATTRIBUTE.equals(childDataModel.getFormat())) continue;
retVal.put(xmlKey, childDataModel);
}
return retVal;
}
public Map getAllElementChildren() {
Map retVal = new LinkedHashMap();
for (Map.Entry candidate : allChildren.entrySet()) {
QName xmlKey = candidate.getKey();
ChildDescriptor childDescriptor = candidate.getValue();
if (childDescriptor.getParentedModel() != null) {
// Is an element since it is a child!
retVal.put(xmlKey, childDescriptor);
continue;
}
ChildDataModel childDataModel = childDescriptor.getChildDataModel();
if (!Format.ELEMENT.equals(childDataModel.getFormat())) continue;
retVal.put(xmlKey, childDescriptor);
}
return retVal;
}
public String getJavaNameFromKey(String key, ClassReflectionHelper reflectionHelper) {
lock.lock();
try {
if (keyToJavaNameMap == null) {
keyToJavaNameMap = new LinkedHashMap();
}
String result = keyToJavaNameMap.get(key);
if (result != null) return result;
if (reflectionHelper == null) return null;
Class> originalInterface = getOriginalInterfaceAsClass();
for (MethodWrapper wrapper : reflectionHelper.getAllMethods(originalInterface)) {
Method m = wrapper.getMethod();
String xmlName;
XmlElement element = m.getAnnotation(XmlElement.class);
if (element == null) {
XmlAttribute attribute = m.getAnnotation(XmlAttribute.class);
if (attribute == null) continue;
xmlName = attribute.name();
}
else {
xmlName = element.name();
}
String keyName;
String javaName = getJavaNameFromGetterOrSetter(m, reflectionHelper);
if ("##default".equals(xmlName)) {
keyName = javaName;
}
else {
keyName = xmlName;
}
if (!key.equals(keyName)) continue;
// Found it!
keyToJavaNameMap.put(key, javaName);
return javaName;
}
return null;
} finally {
lock.unlock();
}
}
private static String getJavaNameFromGetterOrSetter(Method m, ClassReflectionHelper reflectionHelper) {
AltMethod alt = new MethodAltMethodImpl(m, reflectionHelper);
String retVal = Utilities.isGetter(alt);
if (retVal != null) return retVal;
return Utilities.isSetter(alt);
}
@Override
public int hashCode() {
return translatedClass.hashCode();
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof ModelImpl)) return false;
return translatedClass.equals(((ModelImpl) o).getTranslatedClass());
}
@Override
public String toString() {
return "ModelImpl(interface=" + originalInterface +
",class=" + translatedClass +
",root=" + rootName +
",keyProperty=" + keyProperty +
",valuePropertyNamespace=" + valuePropertyNamespace +
",valueProperty=" + valueProperty +
"," + System.identityHashCode(this) + ")";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy