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.tools.internal.xjc.addon.episode; 27 28 import java.io.File; 29 import java.io.FileOutputStream; 30 import java.io.IOException; 31 import java.io.OutputStream; 32 import java.util.ArrayList; 33 import java.util.HashMap; 34 import java.util.HashSet; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Set; 38 39 import com.sun.tools.internal.xjc.BadCommandLineException; 40 import com.sun.tools.internal.xjc.Options; 41 import com.sun.tools.internal.xjc.Plugin; 42 import com.sun.tools.internal.xjc.outline.ClassOutline; 43 import com.sun.tools.internal.xjc.outline.Outline; 44 import com.sun.tools.internal.xjc.outline.EnumOutline; 45 import com.sun.tools.internal.xjc.reader.Const; 46 import com.sun.xml.internal.txw2.TXW; 47 import com.sun.xml.internal.txw2.output.StreamSerializer; 48 import com.sun.xml.internal.xsom.XSAnnotation; 49 import com.sun.xml.internal.xsom.XSAttGroupDecl; 50 import com.sun.xml.internal.xsom.XSAttributeDecl; 51 import com.sun.xml.internal.xsom.XSAttributeUse; 52 import com.sun.xml.internal.xsom.XSComplexType; 53 import com.sun.xml.internal.xsom.XSComponent; 54 import com.sun.xml.internal.xsom.XSContentType; 55 import com.sun.xml.internal.xsom.XSDeclaration; 56 import com.sun.xml.internal.xsom.XSElementDecl; 57 import com.sun.xml.internal.xsom.XSFacet; 58 import com.sun.xml.internal.xsom.XSIdentityConstraint; 59 import com.sun.xml.internal.xsom.XSModelGroup; 60 import com.sun.xml.internal.xsom.XSModelGroupDecl; 61 import com.sun.xml.internal.xsom.XSNotation; 62 import com.sun.xml.internal.xsom.XSParticle; 63 import com.sun.xml.internal.xsom.XSSchema; 64 import com.sun.xml.internal.xsom.XSSimpleType; 65 import com.sun.xml.internal.xsom.XSWildcard; 66 import com.sun.xml.internal.xsom.XSXPath; 67 import com.sun.xml.internal.xsom.visitor.XSFunction; 68 import com.sun.xml.internal.bind.v2.schemagen.episode.Bindings; 69 import com.sun.xml.internal.bind.v2.schemagen.episode.SchemaBindings; 70 71 import org.xml.sax.ErrorHandler; 72 import org.xml.sax.SAXException; 73 import org.xml.sax.SAXParseException; 74 75 /** 76 * Creates the episode file, 77 * 78 * @author Kohsuke Kawaguchi 79 * @author Ben Tomasini (ben.tomasini@gmail.com) 80 */ 81 public class PluginImpl extends Plugin { 82 83 private File episodeFile; 84 85 public String getOptionName() { 86 return "episode"; 87 } 88 89 public String getUsage() { 90 return " -episode <FILE> : generate the episode file for separate compilation"; 91 } 92 93 public int parseArgument(Options opt, String[] args, int i) throws BadCommandLineException, IOException { 94 if(args[i].equals("-episode")) { 95 episodeFile = new File(opt.requireArgument("-episode",args,++i)); 96 return 2; 97 } 98 return 0; 99 } 100 101 /** 102 * Capture all the generated classes from global schema components 103 * and generate them in an episode file. 104 */ 105 public boolean run(Outline model, Options opt, ErrorHandler errorHandler) throws SAXException { 106 try { 107 // reorganize qualifying components by their namespaces to 108 // generate the list nicely 109 Map<XSSchema, PerSchemaOutlineAdaptors> perSchema = new HashMap<XSSchema,PerSchemaOutlineAdaptors>(); 110 boolean hasComponentInNoNamespace = false; 111 112 // Combine classes and enums into a single list 113 List<OutlineAdaptor> outlines = new ArrayList<OutlineAdaptor>(); 114 115 for (ClassOutline co : model.getClasses()) { 116 XSComponent sc = co.target.getSchemaComponent(); 117 String fullName = co.implClass.fullName(); 118 String packageName = co.implClass.getPackage().name(); 119 OutlineAdaptor adaptor = new OutlineAdaptor(sc, 120 OutlineAdaptor.OutlineType.CLASS, fullName, packageName); 121 outlines.add(adaptor); 122 } 123 124 for (EnumOutline eo : model.getEnums()) { 125 XSComponent sc = eo.target.getSchemaComponent(); 126 String fullName = eo.clazz.fullName(); 127 String packageName = eo.clazz.getPackage().name(); 128 OutlineAdaptor adaptor = new OutlineAdaptor(sc, 129 OutlineAdaptor.OutlineType.ENUM, fullName, packageName); 130 outlines.add(adaptor); 131 } 132 133 for (OutlineAdaptor oa : outlines) { 134 XSComponent sc = oa.schemaComponent; 135 136 if (sc == null) continue; 137 if (!(sc instanceof XSDeclaration)) 138 continue; 139 XSDeclaration decl = (XSDeclaration) sc; 140 if (decl.isLocal()) 141 continue; // local components cannot be referenced from outside, so no need to list. 142 143 PerSchemaOutlineAdaptors list = perSchema.get(decl.getOwnerSchema()); 144 if (list == null) { 145 list = new PerSchemaOutlineAdaptors(); 146 perSchema.put(decl.getOwnerSchema(), list); 147 } 148 149 list.add(oa); 150 151 if (decl.getTargetNamespace().equals("")) 152 hasComponentInNoNamespace = true; 153 } 154 155 OutputStream os = new FileOutputStream(episodeFile); 156 Bindings bindings = TXW.create(Bindings.class, new StreamSerializer(os, "UTF-8")); 157 if(hasComponentInNoNamespace) // otherwise jaxb binding NS should be the default namespace 158 bindings._namespace(Const.JAXB_NSURI,"jaxb"); 159 else 160 bindings._namespace(Const.JAXB_NSURI,""); 161 bindings.version("2.1"); 162 bindings._comment("\n\n"+opt.getPrologComment()+"\n "); 163 164 // generate listing per schema 165 for (Map.Entry<XSSchema,PerSchemaOutlineAdaptors> e : perSchema.entrySet()) { 166 PerSchemaOutlineAdaptors ps = e.getValue(); 167 Bindings group = bindings.bindings(); 168 String tns = e.getKey().getTargetNamespace(); 169 if(!tns.equals("")) 170 group._namespace(tns,"tns"); 171 172 group.scd("x-schema::"+(tns.equals("")?"":"tns")); 173 SchemaBindings schemaBindings = group.schemaBindings(); 174 schemaBindings.map(false); 175 if (ps.packageNames.size() == 1) 176 { 177 final String packageName = ps.packageNames.iterator().next(); 178 if (packageName != null && packageName.length() > 0) { 179 schemaBindings._package().name(packageName); 180 } 181 } 182 183 for (OutlineAdaptor oa : ps.outlineAdaptors) { 184 Bindings child = group.bindings(); 185 oa.buildBindings(child); 186 } 187 group.commit(true); 188 } 189 190 bindings.commit(); 191 192 return true; 193 } catch (IOException e) { 194 errorHandler.error(new SAXParseException("Failed to write to "+episodeFile,null,e)); 195 return false; 196 } 197 } 198 199 /** 200 * Computes SCD. 201 * This is fairly limited as JAXB can only map a certain kind of components to classes. 202 */ 203 private static final XSFunction<String> SCD = new XSFunction<String>() { 204 private String name(XSDeclaration decl) { 205 if(decl.getTargetNamespace().equals("")) 206 return decl.getName(); 207 else 208 return "tns:"+decl.getName(); 209 } 210 211 public String complexType(XSComplexType type) { 212 return "~"+name(type); 213 } 214 215 public String simpleType(XSSimpleType simpleType) { 216 return "~"+name(simpleType); 217 } 218 219 public String elementDecl(XSElementDecl decl) { 220 return name(decl); 221 } 222 223 // the rest is doing nothing 224 public String annotation(XSAnnotation ann) { 225 throw new UnsupportedOperationException(); 226 } 227 228 public String attGroupDecl(XSAttGroupDecl decl) { 229 throw new UnsupportedOperationException(); 230 } 231 232 public String attributeDecl(XSAttributeDecl decl) { 233 throw new UnsupportedOperationException(); 234 } 235 236 public String attributeUse(XSAttributeUse use) { 237 throw new UnsupportedOperationException(); 238 } 239 240 public String schema(XSSchema schema) { 241 throw new UnsupportedOperationException(); 242 } 243 244 public String facet(XSFacet facet) { 245 throw new UnsupportedOperationException(); 246 } 247 248 public String notation(XSNotation notation) { 249 throw new UnsupportedOperationException(); 250 } 251 252 public String identityConstraint(XSIdentityConstraint decl) { 253 throw new UnsupportedOperationException(); 254 } 255 256 public String xpath(XSXPath xpath) { 257 throw new UnsupportedOperationException(); 258 } 259 260 public String particle(XSParticle particle) { 261 throw new UnsupportedOperationException(); 262 } 263 264 public String empty(XSContentType empty) { 265 throw new UnsupportedOperationException(); 266 } 267 268 public String wildcard(XSWildcard wc) { 269 throw new UnsupportedOperationException(); 270 } 271 272 public String modelGroupDecl(XSModelGroupDecl decl) { 273 throw new UnsupportedOperationException(); 274 } 275 276 public String modelGroup(XSModelGroup group) { 277 throw new UnsupportedOperationException(); 278 } 279 }; 280 281 private final static class OutlineAdaptor { 282 283 private enum OutlineType { 284 285 CLASS(new BindingsBuilder() { 286 public void build(OutlineAdaptor adaptor, Bindings bindings) { 287 bindings.klass().ref(adaptor.implName); 288 289 } 290 }), 291 ENUM(new BindingsBuilder() { 292 public void build(OutlineAdaptor adaptor, Bindings bindings) { 293 bindings.typesafeEnumClass().ref(adaptor.implName); 294 } 295 }); 296 297 private final BindingsBuilder bindingsBuilder; 298 299 private OutlineType(BindingsBuilder bindingsBuilder) { 300 this.bindingsBuilder = bindingsBuilder; 301 } 302 303 private interface BindingsBuilder { 304 void build(OutlineAdaptor adaptor, Bindings bindings); 305 } 306 307 }; 308 309 private final XSComponent schemaComponent; 310 private final OutlineType outlineType; 311 private final String implName; 312 private final String packageName; 313 314 public OutlineAdaptor(XSComponent schemaComponent, OutlineType outlineType, 315 String implName, String packageName) { 316 this.schemaComponent = schemaComponent; 317 this.outlineType = outlineType; 318 this.implName = implName; 319 this.packageName = packageName; 320 } 321 322 private void buildBindings(Bindings bindings) { 323 bindings.scd(schemaComponent.apply(SCD)); 324 outlineType.bindingsBuilder.build(this, bindings); 325 } 326 } 327 328 private final static class PerSchemaOutlineAdaptors { 329 330 private final List<OutlineAdaptor> outlineAdaptors = new ArrayList<OutlineAdaptor>(); 331 332 private final Set<String> packageNames = new HashSet<String>(); 333 334 private void add(OutlineAdaptor outlineAdaptor) 335 { 336 this.outlineAdaptors.add(outlineAdaptor); 337 this.packageNames.add(outlineAdaptor.packageName); 338 } 339 340 } 341 }