1 /* 2 * Copyright (c) 1997, 2013, 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.ws.spi.db; 27 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.logging.Level; 31 import java.util.logging.Logger; 32 33 import javax.xml.bind.JAXBContext; 34 import javax.xml.bind.Marshaller; 35 36 37 import com.oracle.webservices.internal.api.databinding.DatabindingModeFeature; 38 import com.sun.xml.internal.ws.db.glassfish.JAXBRIContextFactory; 39 import com.sun.xml.internal.ws.util.ServiceConfigurationError; 40 import com.sun.xml.internal.ws.util.ServiceFinder; 41 42 /** 43 * BindingContextFactory 44 * 45 * @author shih-chang.chen@oracle.com 46 */ 47 abstract public class BindingContextFactory { 48 public static final String DefaultDatabindingMode = DatabindingModeFeature.GLASSFISH_JAXB; 49 public static final String JAXB_CONTEXT_FACTORY_PROPERTY = BindingContextFactory.class.getName(); 50 public static final Logger LOGGER = Logger.getLogger(BindingContextFactory.class.getName()); 51 52 // This iterator adds exception checking for proper logging. 53 public static Iterator<BindingContextFactory> serviceIterator() { 54 final ServiceFinder<BindingContextFactory> sf = ServiceFinder 55 .find(BindingContextFactory.class); 56 final Iterator<BindingContextFactory> ibcf = sf.iterator(); 57 58 return new Iterator<BindingContextFactory>() { 59 private BindingContextFactory bcf; 60 61 public boolean hasNext() { 62 while (true) { 63 try { 64 if (ibcf.hasNext()) { 65 bcf = ibcf.next(); 66 return true; 67 } else 68 return false; 69 } catch (ServiceConfigurationError e) { 70 LOGGER.warning("skipping factory: ServiceConfigurationError: " 71 + e.getMessage()); 72 } catch (NoClassDefFoundError ncdfe) { 73 LOGGER.fine("skipping factory: NoClassDefFoundError: " 74 + ncdfe.getMessage()); 75 } 76 } 77 } 78 79 public BindingContextFactory next() { 80 if (LOGGER.isLoggable(Level.FINER)) 81 LOGGER.finer("SPI found provider: " + 82 bcf.getClass().getName()); 83 return bcf; 84 } 85 86 public void remove() { 87 throw new UnsupportedOperationException(); 88 } 89 }; 90 } 91 92 static private List<BindingContextFactory> factories() { 93 List<BindingContextFactory> factories = new java.util.ArrayList<BindingContextFactory>(); 94 Iterator<BindingContextFactory> ibcf = serviceIterator(); 95 while (ibcf.hasNext()) 96 factories.add(ibcf.next()); 97 98 // There should always be at least one factory available. 99 if (factories.isEmpty()) { 100 if (LOGGER.isLoggable(Level.FINER)) 101 LOGGER.log(Level.FINER, "No SPI providers for BindingContextFactory found, adding: " 102 + JAXBRIContextFactory.class.getName()); 103 factories.add(new JAXBRIContextFactory()); 104 } 105 return factories; 106 } 107 108 abstract protected BindingContext newContext(JAXBContext context); 109 110 abstract protected BindingContext newContext(BindingInfo bi); 111 112 /** 113 * Check to see if the BindingContextFactory is for the databinding mode/flavor. The 114 * String parameter can be the package name of the JAXBContext implementation as well. 115 * @param databinding mode/flavor or the package name of the JAXBContext implementation. 116 * @return 117 */ 118 abstract protected boolean isFor(String databinding); 119 120 /** 121 * @deprecated - Does jaxws need this? 122 */ 123 abstract protected BindingContext getContext(Marshaller m); 124 125 static private BindingContextFactory getFactory(String mode) { 126 for (BindingContextFactory f: factories()) { 127 if (f.isFor(mode)) 128 return f; 129 } 130 return null; 131 } 132 133 static public BindingContext create(JAXBContext context) throws DatabindingException { 134 return getJAXBFactory(context).newContext(context); 135 } 136 137 static public BindingContext create(BindingInfo bi) { 138 // Any mode configured in AbstractSEIModelImpl trumps all. 139 // System property comes next, then SPI-located. 140 String mode = bi.getDatabindingMode(); 141 if (mode != null) { 142 if (LOGGER.isLoggable(Level.FINE)) 143 LOGGER.log(Level.FINE, "Using SEI-configured databindng mode: " 144 + mode); 145 } else if ((mode = System.getProperty("BindingContextFactory")) != null) { 146 // The following is left for backward compatibility and should 147 // eventually be removed. 148 bi.setDatabindingMode(mode); 149 if (LOGGER.isLoggable(Level.FINE)) 150 LOGGER.log(Level.FINE, "Using databindng: " + mode 151 + " based on 'BindingContextFactory' System property"); 152 } else if ((mode = System.getProperty(JAXB_CONTEXT_FACTORY_PROPERTY)) != null) { 153 bi.setDatabindingMode(mode); 154 if (LOGGER.isLoggable(Level.FINE)) 155 LOGGER.log(Level.FINE, "Using databindng: " + mode 156 + " based on '" + JAXB_CONTEXT_FACTORY_PROPERTY 157 + "' System property"); 158 } else { 159 // Find a default provider. Note we always ensure the list 160 // is always non-empty. 161 for (BindingContextFactory factory : factories()) { 162 if (LOGGER.isLoggable(Level.FINE)) 163 LOGGER.log(Level.FINE, 164 "Using SPI-determined databindng mode: " 165 + factory.getClass().getName()); 166 // Special case: no name lookup used. 167 return factory.newContext(bi); 168 } 169 170 // Should never get here as the list is non-empty. 171 LOGGER.log(Level.SEVERE, "No Binding Context Factories found."); 172 throw new DatabindingException("No Binding Context Factories found."); 173 } 174 BindingContextFactory f = getFactory(mode); 175 if (f != null) 176 return f.newContext(bi); 177 LOGGER.severe("Unknown Databinding mode: " + mode); 178 throw new DatabindingException("Unknown Databinding mode: " + mode); 179 } 180 181 static public boolean isContextSupported(Object o) { 182 if (o == null) return false; 183 String pkgName = o.getClass().getPackage().getName(); 184 for (BindingContextFactory f: factories()) if (f.isFor(pkgName)) return true; 185 return false; 186 } 187 188 static BindingContextFactory getJAXBFactory(Object o) { 189 String pkgName = o.getClass().getPackage().getName(); 190 BindingContextFactory f = getFactory(pkgName); 191 if (f != null) return f; 192 throw new DatabindingException("Unknown JAXBContext implementation: " + o.getClass()); 193 194 } 195 196 /** 197 * @deprecated - Does jaxws need this? 198 */ 199 static public BindingContext getBindingContext(Marshaller m) { 200 return getJAXBFactory(m).getContext(m); 201 } 202 203 /** 204 * Creates a new {@link BindingContext}. 205 * 206 * <p> 207 * {@link JAXBContext#newInstance(Class[]) JAXBContext.newInstance()} methods may 208 * return other JAXB providers that are not compatible with the JAX-RPC RI. 209 * This method guarantees that the JAX-WS RI will finds the JAXB RI. 210 * 211 * @param classes 212 * Classes to be bound. See {@link JAXBContext#newInstance(Class[])} for the meaning. 213 * @param typeRefs 214 * See {@link #TYPE_REFERENCES} for the meaning of this parameter. 215 * Can be null. 216 * @param subclassReplacements 217 * See {@link #SUBCLASS_REPLACEMENTS} for the meaning of this parameter. 218 * Can be null. 219 * @param defaultNamespaceRemap 220 * See {@link #DEFAULT_NAMESPACE_REMAP} for the meaning of this parameter. 221 * Can be null (and should be null for ordinary use of JAXB.) 222 * @param c14nSupport 223 * See {@link #CANONICALIZATION_SUPPORT} for the meaning of this parameter. 224 * @param ar 225 * See {@link #ANNOTATION_READER} for the meaning of this parameter. 226 * Can be null. 227 * @since JAXB 2.1 EA2 228 */ 229 // public static BindingContext newInstance(@NotNull Class[] classes, 230 // @Nullable Collection<TypeInfo> typeRefs, 231 // @Nullable Map<Class,Class> subclassReplacements, 232 // @Nullable String defaultNamespaceRemap, boolean c14nSupport, 233 // @Nullable RuntimeAnnotationReader ar) throws JAXBException { 234 // return ContextFactory.createContext(classes, typeRefs, subclassReplacements, 235 // defaultNamespaceRemap, c14nSupport, ar, false, false, false); 236 // } 237 // 238 // /** 239 // * @deprecated 240 // * Compatibility with older versions. 241 // */ 242 // public static BindingContext newInstance(@NotNull Class[] classes, 243 // @Nullable Collection<TypeInfo> typeRefs, 244 // @Nullable String defaultNamespaceRemap, boolean c14nSupport ) throws JAXBException { 245 // return newInstance(classes,typeRefs, Collections.<Class,Class>emptyMap(), 246 // defaultNamespaceRemap,c14nSupport,null); 247 // } 248 }