1 /* 2 * Copyright (c) 1997, 2012, 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 26 package com.sun.xml.internal.bind.v2.runtime.property; 27 28 import java.lang.reflect.Constructor; 29 import java.lang.reflect.InvocationTargetException; 30 import java.util.Collection; 31 32 import com.sun.xml.internal.bind.v2.model.core.ID; 33 import com.sun.xml.internal.bind.v2.model.core.PropertyKind; 34 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeAttributePropertyInfo; 35 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeElementPropertyInfo; 36 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeNonElement; 37 import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo; 38 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeInfo; 39 import com.sun.xml.internal.bind.v2.model.runtime.RuntimeValuePropertyInfo; 40 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; 41 42 /** 43 * Create {@link Property} objects. 44 * 45 * @author Kohsuke Kawaguchi (kk@kohsuke.org) 46 */ 47 public abstract class PropertyFactory { 48 private PropertyFactory() {} 49 50 51 /** 52 * Constructors of the {@link Property} implementation. 53 */ 54 private static final Constructor<? extends Property>[] propImpls; 55 56 static { 57 Class<? extends Property>[] implClasses = new Class[] { 58 SingleElementLeafProperty.class, 59 null, // single reference leaf --- but there's no such thing as "reference leaf" 60 null, // no such thing as "map leaf" 61 62 ArrayElementLeafProperty.class, 63 null, // array reference leaf --- but there's no such thing as "reference leaf" 64 null, // no such thing as "map leaf" 65 66 SingleElementNodeProperty.class, 67 SingleReferenceNodeProperty.class, 68 SingleMapNodeProperty.class, 69 70 ArrayElementNodeProperty.class, 71 ArrayReferenceNodeProperty.class, 72 null, // map is always a single property (Map doesn't implement Collection) 73 }; 74 75 propImpls = new Constructor[implClasses.length]; 76 for( int i=0; i<propImpls.length; i++ ) { 77 if(implClasses[i]!=null) 78 // this pointless casting necessary for Mustang 79 propImpls[i] = (Constructor)implClasses[i].getConstructors()[0]; 80 } 81 } 82 83 /** 84 * Creates/obtains a properly configured {@link Property} 85 * object from the given description. 86 */ 87 public static Property create( JAXBContextImpl grammar, RuntimePropertyInfo info ) { 88 89 PropertyKind kind = info.kind(); 90 91 switch(kind) { 92 case ATTRIBUTE: 93 return new AttributeProperty(grammar,(RuntimeAttributePropertyInfo)info); 94 case VALUE: 95 return new ValueProperty(grammar,(RuntimeValuePropertyInfo)info); 96 case ELEMENT: 97 if(((RuntimeElementPropertyInfo)info).isValueList()) 98 return new ListElementProperty(grammar,(RuntimeElementPropertyInfo) info); 99 break; 100 case REFERENCE: 101 case MAP: 102 break; 103 default: 104 assert false; 105 } 106 107 108 boolean isCollection = info.isCollection(); 109 boolean isLeaf = isLeaf(info); 110 111 Constructor<? extends Property> c = propImpls[(isLeaf?0:6)+(isCollection?3:0)+kind.propertyIndex]; 112 try { 113 return c.newInstance( grammar, info ); 114 } catch (InstantiationException e) { 115 throw new InstantiationError(e.getMessage()); 116 } catch (IllegalAccessException e) { 117 throw new IllegalAccessError(e.getMessage()); 118 } catch (InvocationTargetException e) { 119 Throwable t = e.getCause(); 120 if(t instanceof Error) 121 throw (Error)t; 122 if(t instanceof RuntimeException) 123 throw (RuntimeException)t; 124 125 throw new AssertionError(t); 126 } 127 } 128 129 /** 130 * Look for the case that can be optimized as a leaf, 131 * which is a kind of type whose XML representation is just PCDATA. 132 */ 133 static boolean isLeaf(RuntimePropertyInfo info) { 134 Collection<? extends RuntimeTypeInfo> types = info.ref(); 135 if(types.size()!=1) return false; 136 137 RuntimeTypeInfo rti = types.iterator().next(); 138 if(!(rti instanceof RuntimeNonElement)) return false; 139 140 if(info.id()==ID.IDREF) 141 // IDREF is always handled as leaf -- Transducer maps IDREF String back to an object 142 return true; 143 144 if(((RuntimeNonElement)rti).getTransducer()==null) 145 // Transducer!=null means definitely binds to PCDATA. 146 // even if transducer==null, a referene might be IDREF, 147 // in which case it will still produce PCDATA in this reference. 148 return false; 149 150 if(!info.getIndividualType().equals(rti.getType())) 151 return false; 152 153 return true; 154 } 155 }