blob: 8029ab4997736af35a9f41e2449b6c28b925268e [file] [log] [blame]
/*
* Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package com.sun.tools.xjc.addon.episode;
import com.sun.tools.xjc.BadCommandLineException;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.outline.ClassOutline;
import com.sun.tools.xjc.outline.EnumOutline;
import com.sun.tools.xjc.outline.Outline;
import com.sun.tools.xjc.reader.Const;
import org.glassfish.jaxb.core.v2.schemagen.episode.Bindings;
import org.glassfish.jaxb.core.v2.schemagen.episode.SchemaBindings;
import com.sun.xml.txw2.TXW;
import com.sun.xml.txw2.output.StreamSerializer;
import com.sun.xml.xsom.XSAnnotation;
import com.sun.xml.xsom.XSAttGroupDecl;
import com.sun.xml.xsom.XSAttributeDecl;
import com.sun.xml.xsom.XSAttributeUse;
import com.sun.xml.xsom.XSComplexType;
import com.sun.xml.xsom.XSComponent;
import com.sun.xml.xsom.XSContentType;
import com.sun.xml.xsom.XSDeclaration;
import com.sun.xml.xsom.XSElementDecl;
import com.sun.xml.xsom.XSFacet;
import com.sun.xml.xsom.XSIdentityConstraint;
import com.sun.xml.xsom.XSModelGroup;
import com.sun.xml.xsom.XSModelGroupDecl;
import com.sun.xml.xsom.XSNotation;
import com.sun.xml.xsom.XSParticle;
import com.sun.xml.xsom.XSSchema;
import com.sun.xml.xsom.XSSimpleType;
import com.sun.xml.xsom.XSWildcard;
import com.sun.xml.xsom.XSXPath;
import com.sun.xml.xsom.visitor.XSFunction;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Creates the episode file,
*
* @author Kohsuke Kawaguchi
* @author Ben Tomasini (ben.tomasini@gmail.com)
*/
public class PluginImpl extends Plugin {
private File episodeFile;
public String getOptionName() {
return "episode";
}
public String getUsage() {
return " -episode <FILE> : generate the episode file for separate compilation";
}
public int parseArgument(Options opt, String[] args, int i) throws BadCommandLineException, IOException {
if(args[i].equals("-episode")) {
episodeFile = new File(opt.requireArgument("-episode",args,++i));
return 2;
}
return 0;
}
/**
* Capture all the generated classes from global schema components
* and generate them in an episode file.
*/
public boolean run(Outline model, Options opt, ErrorHandler errorHandler) throws SAXException {
OutputStream episodeFileOutputStream = null;
try {
// reorganize qualifying components by their namespaces to
// generate the list nicely
Map<XSSchema, PerSchemaOutlineAdaptors> perSchema = new LinkedHashMap<XSSchema, PerSchemaOutlineAdaptors>();
boolean hasComponentInNoNamespace = false;
// Combine classes and enums into a single list
List<OutlineAdaptor> outlines = new ArrayList<OutlineAdaptor>();
for (ClassOutline co : model.getClasses()) {
XSComponent sc = co.target.getSchemaComponent();
String fullName = co.implClass.fullName();
String packageName = co.implClass.getPackage().name();
OutlineAdaptor adaptor = new OutlineAdaptor(sc,
OutlineAdaptor.OutlineType.CLASS, fullName, packageName);
outlines.add(adaptor);
}
for (EnumOutline eo : model.getEnums()) {
XSComponent sc = eo.target.getSchemaComponent();
String fullName = eo.clazz.fullName();
String packageName = eo.clazz.getPackage().name();
OutlineAdaptor adaptor = new OutlineAdaptor(sc,
OutlineAdaptor.OutlineType.ENUM, fullName, packageName);
outlines.add(adaptor);
}
for (OutlineAdaptor oa : outlines) {
XSComponent sc = oa.schemaComponent;
if (sc == null) continue;
if (!(sc instanceof XSDeclaration))
continue;
XSDeclaration decl = (XSDeclaration) sc;
if (decl.isLocal())
continue; // local components cannot be referenced from outside, so no need to list.
PerSchemaOutlineAdaptors list = perSchema.get(decl.getOwnerSchema());
if (list == null) {
list = new PerSchemaOutlineAdaptors();
perSchema.put(decl.getOwnerSchema(), list);
}
list.add(oa);
if (decl.getTargetNamespace().equals(""))
hasComponentInNoNamespace = true;
}
episodeFileOutputStream = new FileOutputStream(episodeFile);
Bindings bindings = TXW.create(Bindings.class, new StreamSerializer(episodeFileOutputStream, "UTF-8"));
if(hasComponentInNoNamespace) // otherwise jaxb binding NS should be the default namespace
bindings._namespace(Const.JAXB_NSURI,"jaxb");
else
bindings._namespace(Const.JAXB_NSURI,"");
bindings.version("3.0");
bindings._comment("\n\n"+opt.getPrologComment()+"\n ");
// generate listing per schema
for (Map.Entry<XSSchema,PerSchemaOutlineAdaptors> e : perSchema.entrySet()) {
PerSchemaOutlineAdaptors ps = e.getValue();
Bindings group = bindings.bindings();
String tns = e.getKey().getTargetNamespace();
if(!tns.equals(""))
group._namespace(tns,"tns");
group.scd("x-schema::"+(tns.equals("")?"":"tns"));
SchemaBindings schemaBindings = group.schemaBindings();
schemaBindings.map(false);
if (ps.packageNames.size() == 1) {
final String packageName = ps.packageNames.iterator().next();
if (packageName != null && packageName.length() > 0) {
schemaBindings._package().name(packageName);
}
}
for (OutlineAdaptor oa : ps.outlineAdaptors) {
Bindings child = group.bindings();
oa.buildBindings(child);
}
group.commit(true);
}
bindings.commit();
return true;
} catch (IOException e) {
errorHandler.error(new SAXParseException("Failed to write to "+episodeFile,null,e));
return false;
} finally {
if (episodeFileOutputStream != null) {
try {
episodeFileOutputStream.close();
} catch (IOException e) {
errorHandler.error(new SAXParseException("Failed to close file handle for "+episodeFile,null,e));
}
}
}
}
/**
* Computes SCD.
* This is fairly limited as JAXB can only map a certain kind of components to classes.
*/
private static final XSFunction<String> SCD = new XSFunction<String>() {
private String name(XSDeclaration decl) {
if(decl.getTargetNamespace().equals(""))
return decl.getName();
else
return "tns:"+decl.getName();
}
public String complexType(XSComplexType type) {
return "~"+name(type);
}
public String simpleType(XSSimpleType simpleType) {
return "~"+name(simpleType);
}
public String elementDecl(XSElementDecl decl) {
return name(decl);
}
// the rest is doing nothing
public String annotation(XSAnnotation ann) {
throw new UnsupportedOperationException();
}
public String attGroupDecl(XSAttGroupDecl decl) {
throw new UnsupportedOperationException();
}
public String attributeDecl(XSAttributeDecl decl) {
throw new UnsupportedOperationException();
}
public String attributeUse(XSAttributeUse use) {
throw new UnsupportedOperationException();
}
public String schema(XSSchema schema) {
throw new UnsupportedOperationException();
}
public String facet(XSFacet facet) {
throw new UnsupportedOperationException();
}
public String notation(XSNotation notation) {
throw new UnsupportedOperationException();
}
public String identityConstraint(XSIdentityConstraint decl) {
throw new UnsupportedOperationException();
}
public String xpath(XSXPath xpath) {
throw new UnsupportedOperationException();
}
public String particle(XSParticle particle) {
throw new UnsupportedOperationException();
}
public String empty(XSContentType empty) {
throw new UnsupportedOperationException();
}
public String wildcard(XSWildcard wc) {
throw new UnsupportedOperationException();
}
public String modelGroupDecl(XSModelGroupDecl decl) {
throw new UnsupportedOperationException();
}
public String modelGroup(XSModelGroup group) {
throw new UnsupportedOperationException();
}
};
private final static class OutlineAdaptor {
private enum OutlineType {
CLASS(new BindingsBuilder() {
public void build(OutlineAdaptor adaptor, Bindings bindings) {
bindings.klass().ref(adaptor.implName);
}
}),
ENUM(new BindingsBuilder() {
public void build(OutlineAdaptor adaptor, Bindings bindings) {
bindings.typesafeEnumClass().ref(adaptor.implName);
}
});
private final BindingsBuilder bindingsBuilder;
private OutlineType(BindingsBuilder bindingsBuilder) {
this.bindingsBuilder = bindingsBuilder;
}
private interface BindingsBuilder {
void build(OutlineAdaptor adaptor, Bindings bindings);
}
}
private final XSComponent schemaComponent;
private final OutlineType outlineType;
private final String implName;
private final String packageName;
public OutlineAdaptor(XSComponent schemaComponent, OutlineType outlineType,
String implName, String packageName) {
this.schemaComponent = schemaComponent;
this.outlineType = outlineType;
this.implName = implName;
this.packageName = packageName;
}
private void buildBindings(Bindings bindings) {
bindings.scd(schemaComponent.apply(SCD));
outlineType.bindingsBuilder.build(this, bindings);
}
}
private final static class PerSchemaOutlineAdaptors {
private final List<OutlineAdaptor> outlineAdaptors = new ArrayList<OutlineAdaptor>();
private final Set<String> packageNames = new HashSet<String>();
private void add(OutlineAdaptor outlineAdaptor) {
this.outlineAdaptors.add(outlineAdaptor);
this.packageNames.add(outlineAdaptor.packageName);
}
}
}