/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.xml.ws.server.marshal; import gw.internal.schema.gw.xsd.w3c.xmlschema.Enumeration; import gw.internal.schema.gw.xsd.w3c.xmlschema.Restriction; import gw.internal.schema.gw.xsd.w3c.xmlschema.SimpleType; import gw.internal.schema.gw.xsd.w3c.xmlschema.types.complex.LocalElement; import gw.internal.xml.IXmlLoggerFactory; import gw.internal.xml.Marshaller; import gw.internal.xml.config.XmlServices; import gw.internal.xml.ws.server.WsiServiceInfo; import gw.lang.parser.IParsedElement; import gw.lang.parser.resources.Res; import gw.lang.reflect.IPropertyInfo; import gw.lang.reflect.IRelativeTypeInfo; import gw.lang.reflect.IType; import gw.lang.reflect.ITypeInfo; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.java.IJavaType; import gw.util.concurrent.LockingLazyVar; import gw.xml.XmlElement; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; public class RemotableMarshalInfo extends ClassBasedMarshalInfo { static final LockingLazyVar<IType> _gwRemotableType = new LockingLazyVar<IType>( TypeSystem.getGlobalLock() ) { @Override protected IType init() { return TypeSystem.getByFullName( "gw.pl.util.webservices.GWRemotable" ); } }; static final LockingLazyVar<IType> _gwRemotableEnumType = new LockingLazyVar<IType>( TypeSystem.getGlobalLock() ) { @Override protected IType init() { return TypeSystem.getByFullName( "gw.pl.util.webservices.GWEnumeration" ); } }; public RemotableMarshalInfo(IType type, boolean isComponent) { super( type, isComponent); } static boolean isExportable(IType type) { return _gwRemotableType.get().isAssignableFrom(type); } @Override public void addType(LocalElement element, WsiServiceInfo createInfo) throws Exception { if (!_gwRemotableEnumType.get().isAssignableFrom(getType())) { super.addType(element, createInfo); return; } if ( _isComponent ) { element.setNillable$( true ); } else { element.setMinOccurs$( BigInteger.ZERO ); } SimpleType simpleType = createInfo.getSimpleTypeIfNeededFor(_type); if (simpleType != null) { Restriction restriction = new Restriction(); restriction.setBase$(XS_STRING_QNAME); ArrayList<Enumeration> enumerations = new ArrayList<Enumeration>(); if (_type instanceof IJavaType) { // java enums for (Field field : getFields((IJavaType) _type)) { Enumeration enumEL = new Enumeration(); enumEL.setValue$(field.getName()); enumerations.add(enumEL); } } restriction.setEnumeration$(enumerations); simpleType.setRestriction$(restriction); } element.setType$( createInfo.getQName(_type) ); } @Override public Object unmarshal(XmlElement componentElement, UnmarshalContext context) { if (!_gwRemotableEnumType.get().isAssignableFrom(getType())) { return super.unmarshal(componentElement, context); } final String name = componentElement.getText(); try { final Class clazz = ((IJavaType) getType()).getBackingClass(); final Field field = clazz.getField(name); final int modifiers = field.getModifiers(); if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && clazz.equals(field.getType())) { return field.get(null); } XmlServices.getLogger(IXmlLoggerFactory.Category.XmlUnMarshal).error("Unable to unmarshal " + _type + ": " + name); } catch (Throwable e) { XmlServices.getLogger(IXmlLoggerFactory.Category.XmlUnMarshal).error("Unable to unmarshal " + _type + ": " + name, e); } return null; } @Override public void marshal(XmlElement returnEl, IType type, Object obj, MarshalContext context) { if (!_gwRemotableEnumType.get().isAssignableFrom(getType())) { super.marshal(returnEl, type, obj, context); return; } for (Field field : getFields((IJavaType) getType())) { try { if (field.get(null).equals(obj)) { returnEl.setText(field.getName()); return; } } catch (IllegalAccessException e) { XmlServices.getLogger(IXmlLoggerFactory.Category.XmlMarshal).error("Exception on " + _type + ": " + obj, e); } } XmlServices.getLogger(IXmlLoggerFactory.Category.XmlMarshal).error("Unable to marshal " + _type + ": " + obj); } @Override public void checkType(Marshaller marshaller, IParsedElement parsedElement, String label, IType type, Map<String, Object> seenNamespaces) { if (!_gwRemotableEnumType.get().isAssignableFrom(getType())) { super.checkType(marshaller, parsedElement, label, type, seenNamespaces); return; } if (!(type instanceof IJavaType)) { // java enums parsedElement.addParseException(Res.WS_ERR_Can_Not_Marshal, type.getDisplayName(), label); } else if (getFields((IJavaType) type).size() == 0) { parsedElement.addParseException(Res.WS_ERR_Can_Not_Marshal, type.getDisplayName(), label); } } protected Map<String,IPropertyInfo> getProperties(IType type) { Map<String, IPropertyInfo> rtn = new TreeMap<String,IPropertyInfo>(); ITypeInfo typeInfo = type.getTypeInfo(); if (typeInfo instanceof IRelativeTypeInfo) { IRelativeTypeInfo pogoTI = ((IRelativeTypeInfo) typeInfo); for (IPropertyInfo property : pogoTI.getProperties(_gwRemotableType.get())) { if (property.isPublic() && property.isWritable() && property.isReadable()) { rtn.put(property.getName(), property); } } } return rtn; } private List<Field> getFields(IJavaType type) { List<Field> fields = new ArrayList<Field>(); Class clazz = type.getBackingClass(); for (Field field : clazz.getDeclaredFields()) { final int modifiers = field.getModifiers(); if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && clazz.equals(field.getType())) { fields.add(field); } } return fields; } }