diff options
author | Instrumental <jcgmisc@stl.gathman.org> | 2018-03-26 13:37:04 -0700 |
---|---|---|
committer | Instrumental <jcgmisc@stl.gathman.org> | 2018-03-26 13:48:11 -0700 |
commit | ac1e1ec76e9125206be91a2f32c7104c9392dc9a (patch) | |
tree | 91250899236fa337365f4268e9dc5f1da48907d7 /misc/rosetta/src/main | |
parent | 686d16c26d0435f892de66755ac8bc2383a739d2 (diff) |
AT&T 2.0.19 Code drop, stage 1
Issue-ID: AAF-197
Change-Id: Ie75c6c322e9c4e7982b198cb48439e926c3a1fbd
Signed-off-by: Instrumental <jcgmisc@stl.gathman.org>
Diffstat (limited to 'misc/rosetta/src/main')
38 files changed, 4348 insertions, 0 deletions
diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/InJson.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/InJson.java new file mode 100644 index 00000000..725389c9 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/InJson.java @@ -0,0 +1,154 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Reader; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.rosetta.InJson.State; + +public class InJson implements Parse<Reader, State> { + public Parsed<State> parse(Reader r, Parsed<State> parsed) throws ParseException { + // First things first, if there's a "leftover" event, process that immediately + State state = (State)parsed.state; + if(state.unsent > 0) { + parsed.event = state.unsent; + state.unsent = 0; + return parsed; + } + + int ch; + char c; + StringBuilder sb = parsed.sb; + boolean inQuotes = false, escaped = false; + boolean go = true; + try { + // Gather data from Reader, looking for special characters when not in Quotes + while(go && (ch=r.read())>=0) { + if(state.braces>=0 || ch==Parse.START_OBJ) { // ignore garbage/whitespace before content + c=(char)ch; + // Character is a quote. + if(c=='"') { + if(inQuotes) { + if(escaped) { // if escaped Quote, add to data. + sb.append(c); + escaped = false; + } else { + inQuotes = false; + } + } else { + parsed.isString=true; + inQuotes = true; + } + } else { // Not a Quote + if(inQuotes) { + if(c=='\\') { + if(escaped) { + sb.append("\\\\"); + escaped = false; + } else { + escaped = true; + } + } else { + sb.append(c); + } + } else { + switch(c) { + case ':': + parsed.dataIsName(); + parsed.isString = false; + break; + case Parse.START_OBJ: + if(state.braces++ == 0) { + parsed.event = START_DOC; + state.unsent = c; + } else { + parsed.event = c; + } + go = false; + break; + case Parse.END_OBJ: + if(--state.braces == 0) { + parsed.event = c; + state.unsent = END_DOC; + } else { + parsed.event = c; + } + go = false; + break; + // These three end the data gathering, and send it along with the event that is ending the data gathering + case Parse.NEXT: + if(parsed.name.startsWith("__")) { + parsed.event = Parse.ATTRIB; + parsed.name = parsed.name.substring(2); + } else { + parsed.event = c; + } + go = false; + break; + case Parse.START_ARRAY: + case Parse.END_ARRAY: + parsed.event = c; + go = false; + break; + + // The Escape Sequence, for Quote marks within Quotes + case '\\': + // Ignore these, unless within quotes, at which point data-gather + case ' ': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + break; + // Normal data... gather it + default: + sb.append(c); + } + } + } + } + } + return parsed; + } catch (IOException e) { + throw new ParseException(e); + } + } + + public static class State { + public int braces = 0; + public char unsent = 0; + } + +// @Override + public Parsed<State> newParsed() { + return new Parsed<State>(new State()); // no State needed + } + +// @Override + public TimeTaken start(Env env) { + return env.start("Rosetta JSON In", Env.JSON); + } +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/InXML.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/InXML.java new file mode 100644 index 00000000..51926573 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/InXML.java @@ -0,0 +1,486 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.rosetta.InXML.State; + +public class InXML implements Parse<Reader, State> { + // package on purpose + JaxInfo jaxInfo; + + public InXML(JaxInfo jaxInfo) { + this.jaxInfo = jaxInfo; + } + + public InXML(Class<?> cls, String ... rootNs) throws SecurityException, NoSuchFieldException, ClassNotFoundException, ParseException { + jaxInfo = JaxInfo.build(cls,rootNs); + } + + + // @Override + public Parsed<State> parse(Reader r, Parsed<State> parsed) throws ParseException { + State state = parsed.state; + + // OK, before anything else, see if there is leftover processing, if so, do it! + if(state.unevaluated!=null) { + DerTag dt = state.unevaluated; + state.unevaluated = null; + if(!state.greatExp.eval(parsed, dt))return parsed; + } + + if(state.hasAttributes()) { + Prop prop = state.pop(); + parsed.event = Parse.ATTRIB; + parsed.name = prop.tag; + parsed.sb.append(prop.value); + parsed.isString=true; + return parsed; + } + int ch; + char c; + boolean inQuotes = false, escaped = false; + + StringBuilder sb = parsed.sb, tempSB = new StringBuilder(); + boolean go = true; + + try { + while(go && (ch=r.read())>=0) { + c = (char)ch; + if(c == '"') { + if(state.greatExp instanceof LeafExpectations) { // within a set of Tags, make a Quote + sb.append(c); + } else { + if(inQuotes) { + if(escaped) { + sb.append('\\'); + sb.append(c); + escaped = false; + } else { + inQuotes = false; + } + } else { + parsed.isString=true; + inQuotes = true; + } + } + } else if(inQuotes) { + sb.append(c); + } else if(c=='&') { + XmlEscape.xmlEscape(sb,r); + } else { + switch(c) { + case '<': + DerTag tag=new DerTag().parse(r, tempSB); + go = state.greatExp.eval(parsed, tag); + break; + default: + // don't add Whitespace to start of SB... saves removing later + if(sb.length()>0) { + sb.append(c); + } else if(!Character.isWhitespace(c)) { + sb.append(c); + } + } + } + } + return parsed; + } catch (IOException e) { + throw new ParseException(e); + } + } + + public static final class DerTag { + public String name; + public boolean isEndTag; + public List<Prop> props; + private boolean isXmlInfo; + //private String ns; + + public DerTag() { + name=null; + isEndTag = false; + props = null; + isXmlInfo = false; + } + + public DerTag parse(Reader r, StringBuilder sb) throws ParseException { + int ch; + char c; + boolean inQuotes = false, escaped = false; + boolean go = true; + String tag = null; + + try { + if((ch = r.read())<0) throw new ParseException("Reader content ended before complete"); + if(ch=='?') { + isXmlInfo = true; + } + // TODO Check for !-- comments + do { + c=(char)ch; + if(c=='"') { + if(inQuotes) { + if(escaped) { + sb.append(c); + escaped = false; + } else { + inQuotes = false; + } + } else { + inQuotes = true; + } + } else if(inQuotes) { + sb.append(c); + } else { + switch(c) { + case '/': + isEndTag = true; + break; + case ' ': + endField(tag,sb); + tag = null; + break; + case '>': + endField(tag,sb); + go = false; + break; + case '=': + tag = sb.toString(); + sb.setLength(0); + break; +// case ':': +// ns = sb.toString(); +// sb.setLength(0); +// break; + case '?': + if(!isXmlInfo)sb.append(c); + break; + default: + sb.append(c); + } + } + } while(go && (ch=r.read())>=0); + } catch (IOException e) { + throw new ParseException(e); + } + return this; + } + + private void endField(String tag, StringBuilder sb) { + if(name==null) { + name = sb.toString(); + sb.setLength(0); + } else { + String value = sb.toString(); + sb.setLength(0); + if(tag !=null && value != null) { + if(props==null)props = new ArrayList<Prop>(); + props.add(new Prop(tag,value)); + } + } + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(isEndTag?"End":"Start"); + sb.append(" Tag\n"); + sb.append(" Name: "); + sb.append(name); + if(props!=null) for(Prop p : props) { + sb.append("\n "); + sb.append(p.tag); + sb.append("=\""); + sb.append(p.value); + sb.append('"'); + } + return sb.toString(); + } + } + + private static class ArrayState { + public boolean firstObj = true; + public boolean didNext = false; + } + + public static class State { + public GreatExpectations greatExp; + public DerTag unevaluated; + public Stack<ArrayState> arrayInfo; + private List<Prop> attribs; + private int idx; + public State(JaxInfo ji, DerTag dt) throws ParseException { + greatExp = new RootExpectations(this, ji, null); + unevaluated = null; + attribs = null;; + } + + public boolean hasAttributes() { + return attribs!=null && idx<attribs.size(); + } + + public void push(Prop prop) { + if(attribs==null) { + attribs = new ArrayList<Prop>(); + idx = 0; + } + attribs.add(prop); + } + + public Prop pop() { + Prop rv = null; + if(attribs!=null) { + rv = attribs.get(idx++); + if(idx>=attribs.size())attribs = null; + } + return rv; + } + } + + private static abstract class GreatExpectations { + protected JaxInfo ji; + protected GreatExpectations prev; + private Map<String,String> ns; + + public GreatExpectations(State state, JaxInfo curr, GreatExpectations prev, DerTag derTag) throws ParseException { + this.prev = prev; + ns = null; + ji = getDerived(state, curr,derTag); + } + + public abstract boolean eval(Parsed<State> parsed, DerTag derTag) throws ParseException; + + // Recursively look back for any namespaces + protected Map<String,String> getNS() { + if(ns!=null)return ns; + if(prev!=null) { + return prev.getNS(); + } + return null; + } + + private void addNS(Prop prop) { + Map<String,String> existingNS = getNS(); + if(ns==null)ns = new HashMap<String,String>(); + // First make a copy of previous NSs so that we have everything we need, but can overwrite, if necessary + if(existingNS!=null && ns!=existingNS) { + ns.putAll(ns); + } + ns.put(prop.tag, prop.value); + } + + private JaxInfo getDerived(State state, JaxInfo ji, DerTag derTag) throws ParseException { + if(derTag==null)return ji; + + List<Prop> props = derTag.props; + + Prop derived = null; + if(props!=null) { + // Load Namespaces (if any) + for(Prop prop : props) { + if(prop.tag.startsWith("xmlns:")) { + addNS(prop); + } + } + for(Prop prop : props) { + if(prop.tag.endsWith(":type")) { + int idx = prop.tag.indexOf(':'); + String potentialNS = "xmlns:"+prop.tag.substring(0,idx); + Map<String,String> ns = getNS(); + boolean noNamespace = false; + if(ns==null) { + noNamespace = true; + } else { + String nsVal = ns.get(potentialNS); + if(nsVal==null) noNamespace = true; + else { + derived = new Prop(Parsed.EXTENSION_TAG,prop.value); + state.push(derived); + } + } + if(noNamespace) { + throw new ParseException(prop.tag + " utilizes an invalid Namespace prefix"); + } + } else if(!prop.tag.startsWith("xmlns")) { + state.push(prop); + } + } + } + return derived==null?ji:ji.getDerived(derived.value); + } + } + + private static class RootExpectations extends GreatExpectations { + + public RootExpectations(State state, JaxInfo curr, GreatExpectations prev) throws ParseException { + super(state,curr,prev, null); + } + + // @Override + public boolean eval(Parsed<State> parsed, DerTag derTag) throws ParseException { + if(derTag.isXmlInfo) { + parsed.event = START_DOC; + } else if(ji.name.equals(derTag.name)) { + if(derTag.isEndTag) { + parsed.event = END_DOC; + parsed.state.greatExp = prev; + } else { + //parsed.name = derTag.name; + parsed.event = START_OBJ; + parsed.state.greatExp = new ObjectExpectations(parsed.state,ji, this, false, derTag); + } + } + return false; + } + } + + private static class ObjectExpectations extends GreatExpectations { + private boolean printName; + + public ObjectExpectations(State state, JaxInfo curr, GreatExpectations prev, boolean printName, DerTag derTag) throws ParseException { + super(state, curr, prev, derTag); + this.printName=printName; + } + + // @Override + public boolean eval(Parsed<State> parsed, DerTag derTag) throws ParseException { + if(derTag.isEndTag && ji.name.equals(derTag.name)) { + parsed.state.greatExp = prev; + parsed.event = END_OBJ; + if(printName)parsed.name = ji.name; + } else { + //Standard Members + for(JaxInfo memb : ji.members) { + if(memb.name.equals(derTag.name)) { + parsed.name = memb.name; + if(memb.isArray) { + parsed.state.unevaluated = derTag; // evaluate within Array Context + parsed.event = START_ARRAY; + parsed.state.greatExp = new ArrayExpectations(parsed.state,memb,this); + return false; + } else if(memb.isObject()) { + if(derTag.isEndTag) { + throw new ParseException("Unexpected End Tag </" + derTag.name + '>'); + } else { + parsed.event = START_OBJ; + + parsed.state.greatExp = new ObjectExpectations(parsed.state, memb,this,true,derTag); + return false; + } + } else { // a leaf + if(derTag.isEndTag) { + throw new ParseException("Misplaced End Tag </" + parsed.name + '>'); + } else { + parsed.state.greatExp = new LeafExpectations(parsed.state,memb, this); + return true; // finish out Leaf without returning + } + } + } + } + + throw new ParseException("Unexpected Tag <" + derTag.name + '>'); + } + return false; + } + } + + private static class LeafExpectations extends GreatExpectations { + public LeafExpectations(State state, JaxInfo curr, GreatExpectations prev) throws ParseException { + super(state, curr, prev, null); + } + + // @Override + public boolean eval(Parsed<State> parsed, DerTag derTag) throws ParseException { + if(ji.name.equals(derTag.name) && derTag.isEndTag) { + parsed.event = NEXT; + parsed.isString = ji.isString; + parsed.state.greatExp = prev; + } else { + throw new ParseException("Expected </" + ji.name + '>'); + } + return false; + } + } + + private static class ArrayExpectations extends GreatExpectations { + public ArrayExpectations(State state, JaxInfo ji, GreatExpectations prev) throws ParseException { + super(state, ji, prev,null); + if(state.arrayInfo==null)state.arrayInfo=new Stack<ArrayState>(); + state.arrayInfo.push(new ArrayState()); + } + // @Override + public boolean eval(Parsed<State> parsed, DerTag derTag) throws ParseException { + if(ji.name.equals(derTag.name) && !derTag.isEndTag) { + if(ji.isObject()) { + if(derTag.isEndTag) { + throw new ParseException("Unexpected End Tag </" + derTag.name + '>'); + } else { + ArrayState ai = parsed.state.arrayInfo.peek(); + if(ai.firstObj || ai.didNext) { + ai.firstObj = false; + ai.didNext = false; + parsed.event = START_OBJ; + parsed.name=derTag.name; + parsed.state.greatExp = new ObjectExpectations(parsed.state,ji,this,true, derTag); + } else { + ai.didNext = true; + parsed.event = NEXT; + parsed.state.unevaluated = derTag; + } + } + } else { // a leave + if(derTag.isEndTag) { + throw new ParseException("Misplaced End Tag </" + parsed.name + '>'); + } else { + parsed.state.greatExp = new LeafExpectations(parsed.state, ji, this); + return true; // finish out Leaf without returning + } + } + } else { // Tag now different... Array is done + parsed.state.unevaluated = derTag; + parsed.event=END_ARRAY; + parsed.state.greatExp = prev; + parsed.state.arrayInfo.pop(); + } + return false; + } + } + // @Override + public Parsed<State> newParsed() throws ParseException { + return new Parsed<State>(new State(jaxInfo, null)); + } + + // @Override + public TimeTaken start(Env env) { + return env.start("Rosetta XML In", Env.XML); + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxEval.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxEval.java new file mode 100644 index 00000000..2708aa2f --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxEval.java @@ -0,0 +1,26 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +public interface JaxEval{ + public abstract JaxEval eval(Parsed<?> p) throws ParseException; +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxInfo.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxInfo.java new file mode 100644 index 00000000..5f38c8c7 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxInfo.java @@ -0,0 +1,248 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlSchema; +import javax.xml.bind.annotation.XmlType; +import javax.xml.datatype.XMLGregorianCalendar; + +public class JaxInfo { + private static final String DEFAULT = "##default"; + public static final int DATA = 0; + public static final int ARRAY = 1; + public static final int OBJECT = 2; + + public final String name; + public final Class<?> clss; + public Map<String, JaxInfo> extensions; // Classes, which might be found at runtime, that extend this class. Lazy Instantiation + public final JaxInfo[] members; + public final boolean isArray; + public final boolean isString; + public final boolean required; + public final boolean nillable; + public String ns; + public boolean isObject() {return members!=null;} + + private JaxInfo(String n, String ns, Class<?> c, JaxInfo[] members, boolean string, boolean array, boolean required, boolean nillable) { + name = n; + this.ns = ns; + clss = c; + this.members = members; + this.isString = string; + isArray = array; + this.required = required; + this.nillable = nillable; + extensions = null; + } + + + public int getType() { + if(isArray)return ARRAY; + else if(members!=null)return OBJECT; + return DATA; + } + + public JaxInfo getDerived(String derivedName) { + JaxInfo derived; + // Lazy Instantiation + if(extensions == null) { + extensions = new HashMap<String,JaxInfo>(); + derived = null; + } else { + derived = extensions.get(derivedName); + } + + if(derived == null) { + //TODO for the moment, Classes are in same package + Package pkg = clss.getPackage(); + try { + Class<?> dc = getClass().getClassLoader().loadClass(pkg.getName()+'.'+Character.toUpperCase(derivedName.charAt(0))+derivedName.substring(1)); + derived = JaxInfo.build(dc, this); // Use this JAXInfo's name so the tags are correct + extensions.put(derivedName, derived); + } catch (Exception e) { + e.printStackTrace(); + } + } + return derived; + } + + public static JaxInfo get(JaxInfo[] fields, String name) { + for(JaxInfo f : fields) { + if(name.equals(f.name)) return f; + } + return null; + } + + /** + * Build up JAXB Information (recursively) + * + * @param cls + * @param rootNns + * @return + * @throws SecurityException + * @throws NoSuchFieldException + * @throws ClassNotFoundException + * @throws ParseException + */ + public static JaxInfo build(Class<?> cls, JaxInfo parent) throws NoSuchFieldException, ClassNotFoundException, ParseException { + return new JaxInfo(parent.name,parent.ns, cls,buildFields(cls,parent.ns),parent.isString, parent.isArray,parent.required,parent.nillable); + } + /** + * Build up JAXB Information (recursively) + * + * @param cls + * @param rootNns + * @return + * @throws SecurityException + * @throws NoSuchFieldException + * @throws ClassNotFoundException + * @throws ParseException + */ + public static JaxInfo build(Class<?> cls, String ... rootNns) throws SecurityException, NoSuchFieldException, ClassNotFoundException, ParseException { + String defaultNS; + if(rootNns.length>0 && rootNns[0]!=null) { + defaultNS = rootNns[0]; + } else { + Package pkg = cls.getPackage(); + XmlSchema xs = pkg.getAnnotation(XmlSchema.class); + defaultNS = xs==null?"":xs.namespace(); + } + String name; + if(rootNns.length>1) { + name = rootNns[1]; + } else { + XmlRootElement xre = cls.getAnnotation(XmlRootElement.class); + if(xre!=null) { + name = xre.name(); + } else { + XmlType xt = cls.getAnnotation(XmlType.class); + if(xt!=null) { + name=xt.name(); + } else { + throw new ParseException("Need a JAXB Object with XmlRootElement, or stipulate in parms"); + } + } + } + + return new JaxInfo(name,defaultNS, cls,buildFields(cls,defaultNS),false,false,false,false); + } + + // Build up the name and members of this particular class + // This is recursive, if a member is a JAXB Object as well. + private static JaxInfo[] buildFields(Class<?> clazz, String defaultNS) throws SecurityException, NoSuchFieldException, ClassNotFoundException { + ArrayList<JaxInfo> fields = null; // allow for lazy instantiation, because many structures won't have XmlType + Class<?> cls = clazz; + // Build up Method names from JAXB Annotations + XmlType xt; + while((xt = cls.getAnnotation(XmlType.class))!=null) { + if(fields==null)fields = new ArrayList<JaxInfo>(); + for(String field : xt.propOrder()) { + if("".equals(field)) break; // odd bug. "" returned when no fields exist, rather than empty array + Field rf = cls.getDeclaredField(field); + Class<?> ft = rf.getType(); + + boolean required = false; + boolean nillable = false; + String xmlName = field; + String namespace = defaultNS; + + XmlElement xe = rf.getAnnotation(XmlElement.class); + if(xe!=null) { + xmlName=xe.name(); + required = xe.required(); + nillable = false; + if(DEFAULT.equals(xmlName)) { + xmlName = field; + } + namespace = xe.namespace(); + if(DEFAULT.equals(namespace)) { + namespace = defaultNS; + } + } + // If object is a List, then it is possible multiple, per XML/JAXB evaluation + if(ft.isAssignableFrom(List.class)) { + Type t = rf.getGenericType(); + String classname = t.toString(); + int start = classname.indexOf('<'); + int end = classname.indexOf('>'); + Class<?> genClass = Class.forName(classname.substring(start+1, end)); + xe = genClass.getAnnotation(XmlElement.class); + if(xe!=null && !DEFAULT.equals(xe.namespace())) { + namespace = xe.namespace(); + } + // add recursed recursed member, marked as array + fields.add(new JaxInfo(xmlName,namespace,genClass,buildFields(genClass,namespace), genClass.equals(String.class),true,required,nillable)); + } else { + boolean isString = ft.equals(String.class) || ft.equals(XMLGregorianCalendar.class); + // add recursed member + fields.add(new JaxInfo(xmlName,namespace,ft,buildFields(ft,namespace),isString,false,required,nillable)); + } + } + cls = cls.getSuperclass(); + }; + if(fields!=null) { + JaxInfo[] rv = new JaxInfo[fields.size()]; + fields.toArray(rv); + return rv; + } else { + return null; + } + } + + + public StringBuilder dump(StringBuilder sb, int idx) { + for(int i=0;i<idx;++i)sb.append(' '); + sb.append("Field "); + sb.append(name); + sb.append(" ["); + sb.append(clss.getName()); + sb.append("] "); + if(isArray)sb.append(" (array)"); + if(required)sb.append(" (required)"); + if(nillable)sb.append(" (nillable)"); + if(members!=null) { + for(JaxInfo f : members) { + sb.append('\n'); + f.dump(sb,idx+2); + } + } + return sb; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Structure of "); + sb.append(clss.getName()); + sb.append('\n'); + dump(sb,2); + return sb.toString(); + } +}
\ No newline at end of file diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxSet.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxSet.java new file mode 100644 index 00000000..bb6784c8 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/JaxSet.java @@ -0,0 +1,91 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import javax.xml.bind.annotation.XmlType; + +/** + * For specific XML class, quickly find a Setter Method which will load the object + * + * Object type of Setter must match String at this time. + * + * @author Jonathan + * + * @param <T> + */ +public class JaxSet<T> { + private static Map<Class<?>,JaxSet<?>> jsets = new HashMap<Class<?>,JaxSet<?>>(); + private Map<String,Setter<T>> members; + + private JaxSet(Class<?> cls) { + members = new TreeMap<String, Setter<T>>(); + XmlType xmltype = cls.getAnnotation(XmlType.class); + Class<?> paramType[] = new Class[] {String.class}; + for(String str : xmltype.propOrder()) { + try { + String setName = "set" + Character.toUpperCase(str.charAt(0)) + str.subSequence(1, str.length()); + Method meth = cls.getMethod(setName,paramType ); + if(meth!=null) { + members.put(str, new Setter<T>(meth) { + public void set(T o, Object t) throws ParseException { + try { + this.meth.invoke(o, t); + } catch (Exception e) { + throw new ParseException(e); + } + } + }); + } + } catch (Exception e) { + // oops + } + } + } + + public static abstract class Setter<O> { + protected final Method meth; + public Setter(Method meth) { + this.meth = meth; + } + public abstract void set(O o, Object obj) throws ParseException; + } + + public static <X> JaxSet<X> get(Class<?> cls) { + synchronized(jsets) { + @SuppressWarnings("unchecked") + JaxSet<X> js = (JaxSet<X>)jsets.get(cls); + if(js == null) { + jsets.put(cls, js = new JaxSet<X>(cls)); + } + return js; + } + } + + public Setter<T> get(String key) { + return members.get(key); + } +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Ladder.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Ladder.java new file mode 100644 index 00000000..51cec078 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Ladder.java @@ -0,0 +1,113 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + + +/** + * A Ladder is a Stack like Storage Class, but where you can ascend and descend while + * the elements exists. + * + * Like an extension ladder, you can make taller as you go + * + * @author Jonathan + * + */ +public class Ladder<T> { + public static final int DEFAULT_INIT_SIZE=8; + private final int init_size; + private int rung; // as in ladder + private Object[] struts; + + public Ladder() { + rung=0; + init_size = DEFAULT_INIT_SIZE; + struts=new Object[init_size]; + } + + public Ladder(int initSize) { + rung=0; + init_size = initSize; + struts=new Object[init_size]; + } + + public void bottom() { + rung = 0; + } + + public void top() { + rung = struts.length-1; + while(rung>0 && struts[rung]==null)--rung; + } + + public int howHigh() { + return rung; + } + + public void jumpTo(int rung) { + if(rung>=struts.length) { + Object[] temp = new Object[init_size*((rung/init_size)+1)]; + System.arraycopy(struts, 0, temp, 0, struts.length); + struts = temp; + } + this.rung = rung; + } + + public int height() { + return struts.length; + } + + public void cutTo(int rungs) { + Object[] temp = new Object[rungs]; + System.arraycopy(struts, 0, temp, 0, Math.min(rungs, struts.length)); + struts = temp; + } + + public void ascend() { + ++rung; + if(rung>=struts.length) { + Object[] temp = new Object[struts.length+init_size]; + System.arraycopy(struts, 0, temp, 0, struts.length); + struts = temp; + } + } + + public void descend() { + --rung; + } + + @SuppressWarnings("unchecked") + public T peek() { + return (T)struts[rung]; + } + + public void push(T t) { + struts[rung]=t; + } + + @SuppressWarnings("unchecked") + public T pop() { + T t = (T)struts[rung]; + struts[rung]=null; + return t; + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Marshal.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Marshal.java new file mode 100644 index 00000000..d482b247 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Marshal.java @@ -0,0 +1,81 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.util.Iterator; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +public abstract class Marshal<T> implements Parse<T, Marshal.State> { + + /* (non-Javadoc) + * @see org.onap.aaf.misc.rosetta.Parse#newParsed() + */ + @Override + public Parsed<State> newParsed() throws ParseException { + return new Parsed<State>(new State()); + } + + @Override + public TimeTaken start(Env env) { + //TODO is a way to mark not-JSON? + return env.start("Rosetta Marshal", Env.JSON); + }; + + public static class State { + // Note: Need a STATEFUL stack... one that will remain stateful until marked as finished + // "finished" is know by Iterators with no more to do/null + // Thus the concept of "Ladder", which one ascends and decends + public Ladder<Iterator<?>> ladder = new Ladder<Iterator<?>>(); + public boolean smallest = true; + } + + public static final Iterator<Void> DONE_ITERATOR = new Iterator<Void>() { + @Override + public boolean hasNext() { + return false; + } + + @Override + public Void next() { + return null; + } + + @Override + public void remove() { + } + }; + + /** + * Typical definition of Done is when Iterator in Ladder is "DONE_ITERATOR" + * + * It is important, however, that the "Ladder Rung" is set to the right level. + * + * @param state + * @return + */ + public boolean amFinished(State state) { + return DONE_ITERATOR.equals(state.ladder.peek()); + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Nulls.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Nulls.java new file mode 100644 index 00000000..38b021ea --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Nulls.java @@ -0,0 +1,66 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +public class Nulls { + public static final Parse<Reader, ?> IN = new Parse<Reader, Void>() { + + // @Override + public Parsed<Void> parse(Reader r, Parsed<Void> parsed)throws ParseException { + parsed.event = Parse.END_DOC; + return parsed; + } + + // @Override + public Parsed<Void> newParsed() { + Parsed<Void> parsed = new Parsed<Void>(); + parsed.event = Parse.END_DOC; + return parsed; + } + + // @Override + public TimeTaken start(Env env) { + return env.start("IN", Env.SUB); + } + + }; + + public static final Out OUT = new Out() { + + // @Override + public <IN,S> void extract(IN in, Writer writer, Parse<IN, S> parse, boolean ... options)throws IOException, ParseException { + } + @Override + public String logName() { + return "Rosetta NULL"; + } + + + }; +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Out.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Out.java new file mode 100644 index 00000000..567a6261 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Out.java @@ -0,0 +1,43 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +public abstract class Out { + public abstract<IN,S> void extract(IN in, Writer writer, Parse<IN, S> parse, boolean ... options) throws IOException, ParseException; + + public<IN,S> void extract(IN in, OutputStream os, Parse<IN, S> parse, boolean ... options) throws IOException, ParseException { + Writer w = new OutputStreamWriter(os); + try { + extract(in, w, parse, options); + } finally { + w.flush(); + } + } + + public abstract String logName(); + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutJax.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutJax.java new file mode 100644 index 00000000..db7b956c --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutJax.java @@ -0,0 +1,52 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Writer; + +public class OutJax extends Out { + private JaxEval jaxEval; + + public OutJax(JaxEval je) { + this.jaxEval = je; + } + + @Override + public <IN,S> void extract(IN in, Writer writer, Parse<IN, S> parse, boolean... options) throws IOException, ParseException { + Parsed<S> p = parse.newParsed(); + JaxEval je = this.jaxEval; + while((p = parse.parse(in,p.reuse())).valid()) { + if(je==null)throw new ParseException("Incomplete content"); + je = je.eval(p); + } + + } + + @Override + public String logName() { + return "Rosetta JAX"; + } + + + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutJson.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutJson.java new file mode 100644 index 00000000..2340bdb6 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutJson.java @@ -0,0 +1,232 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Writer; +import java.util.Stack; + +import org.onap.aaf.misc.env.util.IndentPrintWriter; + +public class OutJson extends Out { + + @Override + public<IN,S> void extract(IN in, Writer writer, Parse<IN, S> prs, boolean ... options) throws IOException, ParseException { + Parsed<S> p = prs.newParsed(); + IndentPrintWriter ipw; + if(options.length>0 && options[0]) { // is Pretty + ipw = writer instanceof IndentPrintWriter?(IndentPrintWriter)writer:new IndentPrintWriter(writer); + writer = ipw; + } else { + ipw = null; + } + + // If it's a fragment, print first Object Name. If root Object, skip first name + Stack<LevelStack> jsonLevel = new Stack<LevelStack>(); + jsonLevel.push(new LevelStack(options.length>1 && options[1])); + boolean print = true, hadData=false; + char afterName=0, beforeName=0, maybe = 0, prev=0; + + int count = 0; + while((p = prs.parse(in,p.reuse())).valid()) { + ++count; + switch(p.event) { + case 1: + continue; + case 2: + if(count==2) { // it's empty, write open/close on it's own + writer.append('{'); + writer.append('}'); + } + writer.flush(); + return; + case '{': + afterName = '{'; + if(jsonLevel.peek().printObjectName) { + print = true; + } else { // don't print names on first + print=false; + } + maybe=jsonLevel.peek().listItem(); + jsonLevel.push(new LevelStack(true)); + break; + case '}': + if(p.hasData()) { // if we have data, we print that, so may need to prepend a comma. + maybe = jsonLevel.peek().listItem(); + } else { // No data means just print, + p.name = ""; // XML tags come through with names, but no data + } + print = true; + jsonLevel.pop(); + afterName = p.event; + break; + case '[': + afterName = p.event; + if((prev==',' && !hadData) || prev==']')maybe=','; + else maybe = jsonLevel.peek().listItem(); + + jsonLevel.push(new LevelStack(false)); + print=true; + break; + case ']': + afterName = p.event; + if(p.hasData()) { + if(prev==',' && !hadData)maybe=','; + else maybe = jsonLevel.peek().listItem(); + } else { + p.name = ""; // XML tags come through with names, but no data + } + jsonLevel.pop(); + + print = true; + break; + case 3: + case ',': + if(!p.hasData()) { + p.isString=false; + print=false; + } else { + maybe=jsonLevel.peek().listItem(); + print = true; + } + break; + default: + print = true; + } + + if(maybe!=0) { + if(ipw==null)writer.append(maybe); + else ipw.println(maybe); + maybe = 0; + } + + if(beforeName!=0) { + if(ipw==null)writer.append(beforeName); + else ipw.println(beforeName); + beforeName = 0; + } + if(print) { + if(p.hasName()) { + writer.append('"'); + if(p.event==3)writer.append("__"); + writer.append(p.name); + writer.append("\":"); + } + if(p.hasData()) { + if(p.isString) { + writer.append('"'); + escapedWrite(writer, p.sb); + writer.append('"'); + } else if(p.sb.length()>0) { + writer.append(p.sb); + } + } + } + if(afterName!=0) { + if(ipw==null)writer.append(afterName); + else { + switch(afterName) { + case '{': + ipw.println(afterName); + ipw.inc(); + break; + case '}': + ipw.dec(); + ipw.println(); + ipw.print(afterName); + break; + case ']': + if(prev=='}' || prev==',')ipw.println(); + ipw.dec(); + ipw.print(afterName); + break; + + case ',': + ipw.println(afterName); + break; + default: + ipw.print(afterName); + } + } + afterName = 0; + } + + if(ipw!=null) { + switch(p.event) { + case '[': + ipw.inc(); + ipw.println(); + break; + } + } + prev = p.event; + hadData = p.hasData(); + + } + writer.flush(); + } + + private void escapedWrite(Writer writer, StringBuilder sb) throws IOException { + char c; + for(int i=0;i<sb.length();++i) { + switch(c=sb.charAt(i)) { + case '\\': + writer.append(c); + if(i<sb.length()) { + c=sb.charAt(++i); + writer.append(c); + } + break; + case '"': + writer.append('\\'); + // Passthrough on purpose + default: + writer.append(c); + } + } + + + } + + @Override + public String logName() { + return "Rosetta JSON"; + } + + private static class LevelStack { + public boolean printObjectName=false; + private boolean first_n_List=true; + + public LevelStack(boolean printObjectName) { + this.printObjectName = printObjectName; + } + + public char listItem() { + if(first_n_List) { + first_n_List=false; + return 0; + } else { + return ','; + } + } + } +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutRaw.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutRaw.java new file mode 100644 index 00000000..bf833f7b --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutRaw.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Writer; + +public class OutRaw extends Out{ + + @Override + public<IN,S> void extract(IN in, Writer writer, Parse<IN,S> prs, boolean ... options) throws IOException, ParseException { + Parsed<S> p = prs.newParsed(); + + while((p = prs.parse(in,p.reuse())).valid()) { + writer.append(p.toString()); + writer.append('\n'); + } + } + + @Override + public String logName() { + return "Rosetta RAW"; + } + + + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutXML.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutXML.java new file mode 100644 index 00000000..f3ce1c22 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/OutXML.java @@ -0,0 +1,225 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.onap.aaf.misc.env.util.IndentPrintWriter; +import org.onap.aaf.misc.env.util.StringBuilderWriter; + +public class OutXML extends Out{ + private static final String XMLNS_XSI = "xmlns:xsi"; + public static final String XML_INFO = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"; + public static final String XML_SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance"; + + private String root; + private List<Prop> props; + + public OutXML(String root, String ... params) { + this.root = root; + props = new ArrayList<Prop>(); + for(String p : params) { + String[] tv=p.split("="); + if(tv.length==2) + props.add(new Prop(tv[0],tv[1])); + } + } + + public OutXML(JaxInfo jaxInfo) { + this(jaxInfo.name,genNS(jaxInfo)); + } + + public OutXML(InXML inXML) { + this(inXML.jaxInfo.name,genNS(inXML.jaxInfo)); + } + + private static String[] genNS(JaxInfo jaxInfo) { + return new String[] {"xmlns=" + jaxInfo.ns}; + } + + + @Override + public<IN,S> void extract(IN in, Writer writer, Parse<IN,S> prs, boolean ... options) throws IOException, ParseException { + Parsed<S> p = prs.newParsed(); + Stack<Level> stack = new Stack<Level>(); + // If it's an IndentPrintWriter, it is pretty printing. + boolean pretty = (options.length>0&&options[0]); + + IndentPrintWriter ipw; + if(pretty) { + if(writer instanceof IndentPrintWriter) { + ipw = (IndentPrintWriter)writer; + } else { + writer = ipw = new IndentPrintWriter(writer); + } + } else { + ipw=null; + } + boolean closeTag = false; + Level level = new Level(null); + while((p = prs.parse(in,p.reuse())).valid()) { + if(!p.hasName() && level.multi!=null) { + p.name=level.multi; + } + if(closeTag && p.event!=Parse.ATTRIB) { + writer.append('>'); + if(pretty)writer.append('\n'); + closeTag = false; + } + switch(p.event) { + case Parse.START_DOC: + if(!(options.length>1&&options[1])) // if not a fragment, print XML Info data + if(pretty)ipw.println(XML_INFO); + else writer.append(XML_INFO); + break; + case Parse.END_DOC: + break; + case Parse.START_OBJ: + stack.push(level); + level = new Level(level); + if(p.hasName()) { + closeTag = tag(writer,level.sbw,pretty,pretty,p.name,null); + } else if(root!=null && stack.size()==1) { // first Object + closeTag = tag(writer,level.sbw,pretty,pretty,root,null); + // Write Root Props + for(Prop prop : props) { + attrib(writer,pretty,prop.tag, prop.value,level); + } + } + if(pretty)ipw.inc(); + break; + case Parse.END_OBJ: + if(p.hasData()) + closeTag = tag(writer,writer,pretty,false,p.name, XmlEscape.convert(p.sb)); + if(pretty)ipw.dec(); + writer.append(level.sbw.getBuffer()); + level = stack.pop(); + break; + case Parse.START_ARRAY: + level.multi = p.name; + break; + case Parse.END_ARRAY: + if(p.hasData()) + closeTag = tag(writer,writer,pretty,false, p.name, XmlEscape.convert(p.sb)); + level.multi=null; + break; + case Parse.ATTRIB: + if(p.hasData()) + attrib(writer,pretty,p.name, XmlEscape.convert(p.sb), level); + break; + case Parse.NEXT: + if(p.hasData()) + closeTag = tag(writer,writer,pretty, false,p.name, XmlEscape.convert(p.sb)); + break; + } + } + writer.append(level.sbw.getBuffer()); + writer.flush(); + } + + private class Level { + public final StringBuilderWriter sbw; + public String multi; + private Level prev; + private Map<String,String> nses; + + public Level(Level level) { + sbw = new StringBuilderWriter(); + multi = null; + prev = level; + } + + public boolean hasPrinted(String ns, String value, boolean create) { + boolean rv = false; + if(nses==null) { + if(prev!=null)rv = prev.hasPrinted(ns, value, false); + } else { + String v = nses.get(ns); + return value.equals(v); // note: accomodates not finding NS as well + } + + if(create && !rv) { + if(nses == null) nses = new HashMap<String,String>(); + nses.put(ns, value); + } + return rv; + } + + + + } + + private boolean tag(Writer fore, Writer aft, boolean pretty, boolean returns, String tag, String data) throws IOException { + fore.append('<'); + fore.append(tag); + if(data!=null) { + fore.append('>'); // if no data, it may need some attributes... + fore.append(data); + if(returns)fore.append('\n'); + } + aft.append("</"); + aft.append(tag); + aft.append(">"); + if(pretty)aft.append('\n'); + return data==null; + } + + private void attrib(Writer fore, boolean pretty, String tag, String value, Level level) throws IOException { + String realTag = tag.startsWith("__")?tag.substring(2):tag; // remove __ + if(realTag.equals(Parsed.EXTENSION_TAG)) { // Convert Derived name into XML defined Inheritance + fore.append(" xsi:type=\""); + fore.append(value); + fore.append('"'); + if(!level.hasPrinted(XMLNS_XSI, XML_SCHEMA_INSTANCE,true)) { + fore.append(' '); + fore.append(XMLNS_XSI); + fore.append("=\""); + fore.append(XML_SCHEMA_INSTANCE); + fore.append("\""); + } + } else { + if(realTag.startsWith("xmlns:") ) { + if(level.hasPrinted(realTag, value, true)) { + return; + } + } + fore.append(' '); + fore.append(realTag); + fore.append("=\""); + fore.append(value); + fore.append('"'); + } + } + + @Override + public String logName() { + return "Rosetta XML"; + } + + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Parse.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Parse.java new file mode 100644 index 00000000..657baf5c --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Parse.java @@ -0,0 +1,45 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +public interface Parse<IN, S> { + public Parsed<S> parse(IN in, Parsed<S> parsed) throws ParseException; + + // EVENTS + public static final char NONE = 0; + public static final char START_DOC = 1; + public static final char END_DOC = 2; + public static final char ATTRIB = 3; + + public static final char NEXT = ','; + public static final char START_OBJ = '{'; + public static final char END_OBJ = '}'; + public static final char START_ARRAY = '['; + public static final char END_ARRAY = ']'; + + public Parsed<S> newParsed() throws ParseException; + public TimeTaken start(Env env); + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/ParseException.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/ParseException.java new file mode 100644 index 00000000..d986776d --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/ParseException.java @@ -0,0 +1,42 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +public class ParseException extends Exception { + private static final long serialVersionUID = 7808836939102997012L; + + public ParseException() { + } + + public ParseException(String message) { + super(message); + } + + public ParseException(Throwable cause) { + super(cause); + } + + public ParseException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Parsed.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Parsed.java new file mode 100644 index 00000000..326c5bba --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Parsed.java @@ -0,0 +1,89 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + + +public class Parsed<S> { + public static final String EXTENSION_TAG="extension"; + + public boolean isString; + + public StringBuilder sb; + public char event; + public String name; + public S state; + + public Parsed() { + this(null); + } + + // Package on purpose + Parsed(S theState) { + sb = new StringBuilder(); + isString = false; + event = Parse.NONE; + name = ""; + state = theState; + } + + public boolean valid() { + return event!=Parse.NONE; + } + + public Parsed<S> reuse() { + isString=false; + sb.setLength(0); + event = Parse.NONE; + name = ""; + // don't touch T... + return this; + } + + public void dataIsName() { + name = sb.toString(); + sb.setLength(0); + } + + public boolean hasName() { + return name.length()>0; + } + + public boolean hasData() { + return sb.length()>0; + } + + public String toString() { + StringBuilder sb2 = new StringBuilder(); + if(event<40)sb2.append((int)event); + else sb2.append(event); + sb2.append(" - "); + sb2.append(name); + if(sb.length()>0) { + sb2.append(" : "); + if(isString)sb2.append('"'); + sb2.append(sb); + if(isString)sb2.append('"'); + } + return sb2.toString(); + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Prop.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Prop.java new file mode 100644 index 00000000..07bd40f0 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Prop.java @@ -0,0 +1,43 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +class Prop { + public String tag; + public String value; + public Prop(String t, String v) { + tag = t; + value =v; + } + + public Prop(String t_equals_v) { + String[] tv = t_equals_v.split("="); + if(tv.length>1) { + tag = tv[0]; + value = tv[1]; + } + } + + public String toString() { + return tag + '=' + value; + } +}
\ No newline at end of file diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Saved.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Saved.java new file mode 100644 index 00000000..45c27052 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/Saved.java @@ -0,0 +1,194 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.List; + +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.rosetta.Saved.State; + +/** + * An Out Object that will save off produced Parsed Stream and + * a Parse (In) Object that will reproduce Parsed Stream on demand + * + * @author Jonathan + * + */ +public class Saved extends Out implements Parse<Reader, State>{ + private static final String ROSETTA_SAVED = "Rosetta Saved"; + private final static int INIT_SIZE=128; + private Content content[]; + private int idx; + private boolean append = false; + + /** + * Read from Parsed Stream and save + */ + // @Override + public<IN,S> void extract(IN in, Writer ignore, Parse<IN,S> parser, boolean ... options) throws IOException, ParseException { + Parsed<S> p = parser.newParsed(); + if(!append) { + // reuse array if not too big + if(content==null||content.length>INIT_SIZE*3) { + content = new Content[INIT_SIZE]; + idx = -1; + } else do { + content[idx]=null; + } while(--idx>=0); + } + + // Note: idx needs to be -1 on initialization and no appendages + while((p = parser.parse(in,p.reuse())).valid()) { + if(!(append && (p.event==START_DOC || p.event==END_DOC))) { // skip any start/end of document in appendages + if(++idx>=content.length) { + Content temp[] = new Content[content.length*2]; + System.arraycopy(content, 0, temp, 0, idx); + content = temp; + } + content[idx]= new Content(p); + } + } + } + + // @Override + public Parsed<State> parse(Reader ignore, Parsed<State> parsed) throws ParseException { + int i; + if((i=parsed.state.count++)<=idx) + content[i].load(parsed); + else + parsed.event = Parse.NONE; + return parsed; + } + + public Content[] cut(char event, int count) { + append = true; + for(int i=idx;i>=0;--i) { + if(content[i].event==event) count--; + if(count==0) { + Content[] appended = new Content[idx-i+1]; + System.arraycopy(content, i, appended, 0, appended.length); + idx = i-1; + return appended; + } + } + return new Content[0]; + } + + public void paste(Content[] appended) { + if(appended!=null) { + if(idx+appended.length>content.length) { + Content temp[] = new Content[content.length*2]; + System.arraycopy(content, 0, temp, 0, idx); + content = temp; + } + System.arraycopy(appended,0,content,idx+1,appended.length); + idx+=appended.length; + } + this.append = false; + } + + public static class State { + public int count = 0; + } + + public static class Content { + private boolean isString; + private char event; + private String name; + private List<Prop> props; + private String str; + + public Content(Parsed<?> p) { + isString = p.isString; + event = p.event; + name = p.name; + // avoid copying, because most elements don't have content + // Cannot set to "equals", because sb ends up being cleared (and reused) + str = p.sb.length()==0?null:p.sb.toString(); + } + + public void load(Parsed<State> p) { + p.isString = isString; + p.event = event; + p.name = name; + if(str!=null) + p.sb.append(str); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(event); + sb.append(" - "); + sb.append(name); + sb.append(": "); + if(isString)sb.append('"'); + sb.append(str); + if(isString)sb.append('"'); + sb.append(' '); + if(props!=null) { + boolean comma = false; + for(Prop prop : props) { + if(comma)sb.append(','); + else comma = true; + sb.append(prop.tag); + sb.append('='); + sb.append(prop.value); + } + } + return sb.toString(); + } + } + + //// @Override + public Parsed<State> newParsed() { + Parsed<State> ps = new Parsed<State>(new State()); + return ps; + } + + /** + * Convenience function + * @param rdr + * @param in + * @throws IOException + * @throws ParseException + */ + public<IN,S> void load(IN in, Parse<IN, S> parser) throws IOException, ParseException { + extract(in,(Writer)null, parser); + } + + + // @Override + public TimeTaken start(Env env) { + return env.start(ROSETTA_SAVED, 0); + } + + @Override + public String logName() { + return ROSETTA_SAVED; + } + + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/XmlEscape.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/XmlEscape.java new file mode 100644 index 00000000..f1cde6e5 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/XmlEscape.java @@ -0,0 +1,371 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta; + +import java.io.IOException; +import java.io.Reader; +import java.util.Map.Entry; +import java.util.TreeMap; + +public class XmlEscape { + private XmlEscape() {} + + private static final TreeMap<String,Integer> charMap; // see initialization at end + private static final TreeMap<Integer,String> intMap; // see initialization at end + + public static void xmlEscape(StringBuilder sb, Reader r) throws ParseException { + try { + int c; + StringBuilder esc = new StringBuilder(); + for(int cnt = 0;cnt<9 /*max*/; ++cnt) { + if((c=r.read())<0)throw new ParseException("Invalid Data: Unfinished Escape Sequence"); + if(c!=';') { + esc.append((char)c); + } else { // evaluate + Integer i = charMap.get(esc.toString()); + if(i==null) { + // leave in nasty XML format for now. + sb.append('&'); + sb.append(esc); + sb.append(';'); + } else { + sb.append((char)i.intValue()); + } + break; + } + } + + + } catch (IOException e) { + throw new ParseException(e); + } + } + + public static void xmlEscape(StringBuilder sb, int chr) { + sb.append('&'); + sb.append(intMap.get(chr)); + sb.append(';'); + } + + public static String convert(StringBuilder insb) { + int idx, ch; + StringBuilder sb=null; + for(idx=0;idx<insb.length();++idx) { + ch = insb.charAt(idx); + if(ch>=160 || ch==34 || ch==38 || ch==39 || ch==60 || ch==62) { + sb = new StringBuilder(); + sb.append(insb,0,idx); + break; + } + } + + if(sb==null)return insb.toString(); + + for(int i=idx;i<insb.length();++i) { + ch = insb.charAt(i); + if(ch<160) { + switch(ch) { + case 34: sb.append("""); break; + case 38: sb.append("&"); break; + case 39: sb.append("'"); break; + case 60: sb.append("<"); break; + case 62: sb.append(">"); break; + default: + sb.append((char)ch); + } + } else { // use map + String s = intMap.get(ch); + if(s==null)sb.append((char)ch); + else { + sb.append('&'); + sb.append(s); + sb.append(';'); + } + } + } + return sb.toString(); + } + + static { + charMap = new TreeMap<String, Integer>(); + intMap = new TreeMap<Integer,String>(); + charMap.put("quot", 34); + charMap.put("amp",38); + charMap.put("apos",39); + charMap.put("lt",60); + charMap.put("gt",62); + charMap.put("nbsp",160); + charMap.put("iexcl",161); + charMap.put("cent",162); + charMap.put("pound",163); + charMap.put("curren",164); + charMap.put("yen",165); + charMap.put("brvbar",166); + charMap.put("sect",167); + charMap.put("uml",168); + charMap.put("copy",169); + charMap.put("ordf",170); + charMap.put("laquo",171); + charMap.put("not",172); + charMap.put("shy",173); + charMap.put("reg",174); + charMap.put("macr",175); + charMap.put("deg",176); + charMap.put("plusmn",177); + charMap.put("sup2",178); + charMap.put("sup3",179); + charMap.put("acute",180); + charMap.put("micro",181); + charMap.put("para",182); + charMap.put("middot",183); + charMap.put("cedil",184); + charMap.put("sup1",185); + charMap.put("ordm",186); + charMap.put("raquo",187); + charMap.put("frac14",188); + charMap.put("frac12",189); + charMap.put("frac34",190); + charMap.put("iquest",191); + charMap.put("Agrave",192); + charMap.put("Aacute",193); + charMap.put("Acirc",194); + charMap.put("Atilde",195); + charMap.put("Auml",196); + charMap.put("Aring",197); + charMap.put("AElig",198); + charMap.put("Ccedil",199); + charMap.put("Egrave",200); + charMap.put("Eacute",201); + charMap.put("Ecirc",202); + charMap.put("Euml",203); + charMap.put("Igrave",204); + charMap.put("Iacute",205); + charMap.put("Icirc",206); + charMap.put("Iuml",207); + charMap.put("ETH",208); + charMap.put("Ntilde",209); + charMap.put("Ograve",210); + charMap.put("Oacute",211); + charMap.put("Ocirc",212); + charMap.put("Otilde",213); + charMap.put("Ouml",214); + charMap.put("times",215); + charMap.put("Oslash",216); + charMap.put("Ugrave",217); + charMap.put("Uacute",218); + charMap.put("Ucirc",219); + charMap.put("Uuml",220); + charMap.put("Yacute",221); + charMap.put("THORN",222); + charMap.put("szlig",223); + charMap.put("agrave",224); + charMap.put("aacute",225); + charMap.put("acirc",226); + charMap.put("atilde",227); + charMap.put("auml",228); + charMap.put("aring",229); + charMap.put("aelig",230); + charMap.put("ccedil",231); + charMap.put("egrave",232); + charMap.put("eacute",233); + charMap.put("ecirc",234); + charMap.put("euml",235); + charMap.put("igrave",236); + charMap.put("iacute",237); + charMap.put("icirc",238); + charMap.put("iuml",239); + charMap.put("eth",240); + charMap.put("ntilde",241); + charMap.put("ograve",242); + charMap.put("oacute",243); + charMap.put("ocirc",244); + charMap.put("otilde",245); + charMap.put("ouml",246); + charMap.put("divide",247); + charMap.put("oslash",248); + charMap.put("ugrave",249); + charMap.put("uacute",250); + charMap.put("ucirc",251); + charMap.put("uuml",252); + charMap.put("yacute",253); + charMap.put("thorn",254); + charMap.put("yuml",255); + charMap.put("OElig",338); + charMap.put("oelig",339); + charMap.put("Scaron",352); + charMap.put("scaron",353); + charMap.put("Yuml",376); + charMap.put("fnof",402); + charMap.put("circ",710); + charMap.put("tilde",732); + charMap.put("Alpha",913); + charMap.put("Beta",914); + charMap.put("Gamma",915); + charMap.put("Delta",916); + charMap.put("Epsilon",917); + charMap.put("Zeta",918); + charMap.put("Eta",919); + charMap.put("Theta",920); + charMap.put("Iota",921); + charMap.put("Kappa",922); + charMap.put("Lambda",923); + charMap.put("Mu",924); + charMap.put("Nu",925); + charMap.put("Xi",926); + charMap.put("Omicron",927); + charMap.put("Pi",928); + charMap.put("Rho",929); + charMap.put("Sigma",931); + charMap.put("Tau",932); + charMap.put("Upsilon",933); + charMap.put("Phi",934); + charMap.put("Chi",935); + charMap.put("Psi",936); + charMap.put("Omega",937); + charMap.put("alpha",945); + charMap.put("beta",946); + charMap.put("gamma",947); + charMap.put("delta",948); + charMap.put("epsilon",949); + charMap.put("zeta",950); + charMap.put("eta",951); + charMap.put("theta",952); + charMap.put("iota",953); + charMap.put("kappa",954); + charMap.put("lambda",955); + charMap.put("mu",956); + charMap.put("nu",957); + charMap.put("xi",958); + charMap.put("omicron",959); + charMap.put("pi",960); + charMap.put("rho",961); + charMap.put("sigmaf",962); + charMap.put("sigma",963); + charMap.put("tau",964); + charMap.put("upsilon",965); + charMap.put("phi",966); + charMap.put("chi",967); + charMap.put("psi",968); + charMap.put("omega",969); + charMap.put("thetasym",977); + charMap.put("upsih",978); + charMap.put("piv",982); + charMap.put("ensp",8194); + charMap.put("emsp",8195); + charMap.put("thinsp",8201); + charMap.put("zwnj",8204); + charMap.put("zwj",8205); + charMap.put("lrm",8206); + charMap.put("rlm",8207); + charMap.put("ndash",8211); + charMap.put("mdash",8212); + charMap.put("lsquo",8216); + charMap.put("rsquo",8217); + charMap.put("sbquo",8218); + charMap.put("ldquo",8220); + charMap.put("rdquo",8221); + charMap.put("bdquo",8222); + charMap.put("dagger",8224); + charMap.put("Dagger",8225); + charMap.put("bull",8226); + charMap.put("hellip",8230); + charMap.put("permil",8240); + charMap.put("prime",8242); + charMap.put("Prime",8243); + charMap.put("lsaquo",8249); + charMap.put("rsaquo",8250); + charMap.put("oline",8254); + charMap.put("frasl",8260); + charMap.put("euro",8364); + charMap.put("image",8465); + charMap.put("weierp",8472); + charMap.put("real",8476); + charMap.put("trade",8482); + charMap.put("alefsym",8501); + charMap.put("larr",8592); + charMap.put("uarr",8593); + charMap.put("rarr",8594); + charMap.put("darr",8595); + charMap.put("harr",8596); + charMap.put("crarr",8629); + charMap.put("lArr",8656); + charMap.put("uArr",8657); + charMap.put("rArr",8658); + charMap.put("dArr",8659); + charMap.put("hArr",8660); + charMap.put("forall",8704); + charMap.put("part",8706); + charMap.put("exist",8707); + charMap.put("empty",8709); + charMap.put("nabla",8711); + charMap.put("isin",8712); + charMap.put("notin",8713); + charMap.put("ni",8715); + charMap.put("prod",8719); + charMap.put("sum",8721); + charMap.put("minus",8722); + charMap.put("lowast",8727); + charMap.put("radic",8730); + charMap.put("prop",8733); + charMap.put("infin",8734); + charMap.put("ang",8736); + charMap.put("and",8743); + charMap.put("or",8744); + charMap.put("cap",8745); + charMap.put("cup",8746); + charMap.put("int",8747); + charMap.put("there4",8756); + charMap.put("sim",8764); + charMap.put("cong",8773); + charMap.put("asymp",8776); + charMap.put("ne",8800); + charMap.put("equiv",8801); + charMap.put("le",8804); + charMap.put("ge",8805); + charMap.put("sub",8834); + charMap.put("sup",8835); + charMap.put("nsub",8836); + charMap.put("sube",8838); + charMap.put("supe",8839); + charMap.put("oplus",8853); + charMap.put("otimes",8855); + charMap.put("perp",8869); + charMap.put("sdot",8901); + charMap.put("lceil",8968); + charMap.put("rceil",8969); + charMap.put("lfloor",8970); + charMap.put("rfloor",8971); + charMap.put("lang",9001); + charMap.put("rang",9002); + charMap.put("loz",9674); + charMap.put("spades",9824); + charMap.put("clubs",9827); + charMap.put("hearts",9829); + charMap.put("diams",9830); + + for( Entry<String, Integer> es: charMap.entrySet()) { + if(es.getValue()>=160); // save small space... note that no longer has amp, etc. + intMap.put(es.getValue(), es.getKey()); + } + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaDF.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaDF.java new file mode 100644 index 00000000..68baebb6 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaDF.java @@ -0,0 +1,265 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.env; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import javax.xml.bind.JAXBException; +import javax.xml.namespace.QName; +import javax.xml.validation.Schema; + +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.BaseDataFactory; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.DataFactory; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.Data.TYPE; +import org.onap.aaf.misc.env.jaxb.JAXBmar; +import org.onap.aaf.misc.env.jaxb.JAXBumar; +import org.onap.aaf.misc.rosetta.InJson; +import org.onap.aaf.misc.rosetta.InXML; +import org.onap.aaf.misc.rosetta.JaxInfo; +import org.onap.aaf.misc.rosetta.Marshal; +import org.onap.aaf.misc.rosetta.Out; +import org.onap.aaf.misc.rosetta.OutJson; +import org.onap.aaf.misc.rosetta.OutRaw; +import org.onap.aaf.misc.rosetta.OutXML; +import org.onap.aaf.misc.rosetta.Parse; +import org.onap.aaf.misc.rosetta.ParseException; +import org.onap.aaf.misc.rosetta.marshal.DocMarshal; + +public class RosettaDF<T> extends BaseDataFactory implements DataFactory<T> { + + static InJson inJSON = new InJson(); + InXML inXML; + + static OutJson outJSON = new OutJson(); + OutXML outXML; + static OutRaw outRAW = new OutRaw(); + + // Temporary until we write JAXB impl... + JAXBmar jaxMar; + JAXBumar jaxUmar; + + private Parse<Reader,?> defaultIn; + private Out defaultOut; + private RosettaEnv env; + private TYPE inType; + private TYPE outType; + private int defOption; + Marshal<T> marshal = null; + + + /** + * Private constructor to setup Type specific data manipulators + * @param schema + * @param rootNs + * @param cls + * @throws SecurityException + * @throws NoSuchFieldException + * @throws ClassNotFoundException + * @throws ParseException + * @throws JAXBException + */ + // package on purpose + RosettaDF(RosettaEnv env, Schema schema, String rootNs, Class<T> cls) throws APIException { + this.env = env; + try { + // Note: rootNs can be null, in order to derive content from Class. + JaxInfo ji = rootNs==null?JaxInfo.build(cls):JaxInfo.build(cls,rootNs); + // Note: JAXBmar sets qname to null if not exists + jaxMar = new JAXBmar(rootNs==null?null:new QName("xmlns",rootNs),cls); + // Note: JAXBumar sets schema to null if not exists + jaxUmar = new JAXBumar(schema, cls); + + defaultIn = inXML = new InXML(ji); + defaultOut = outXML = new OutXML(ji); + inType=outType=Data.TYPE.XML; + defOption = 0; + } catch (Exception e) { + throw new APIException(e); + } + } + + + // @Override + public RosettaData<T> newData() { + RosettaData<T> data = new RosettaData<T>(env, this) + .in(inType) + .out(outType) + .option(defOption); + return data; + } + + // @Override + public RosettaData<T> newData(Env trans) { + RosettaData<T> data = new RosettaData<T>(trans, this) + .in(inType) + .out(outType) + .option(defOption); + return data; + } + + @SuppressWarnings("unchecked") + // @Override + public Class<T> getTypeClass() { + return (Class<T>)jaxMar.getMarshalClass(); + } + + public RosettaDF<T> in(Data.TYPE type) { + inType = type; + defaultIn=getIn(type==Data.TYPE.DEFAULT?Data.TYPE.JSON:type); + return this; + } + + /** + * If exists, first option is "Pretty", second is "Fragment" + * + * @param options + * @return + */ + public RosettaDF<T> out(Data.TYPE type) { + outType = type; + defaultOut = getOut(type==Data.TYPE.DEFAULT?Data.TYPE.JSON:type); + return this; + } + + public Parse<Reader,?> getIn(Data.TYPE type) { + switch(type) { + case DEFAULT: + return defaultIn; + case JSON: + return inJSON; + case XML: + return inXML; + default: + return defaultIn; + } + } + + public Out getOut(Data.TYPE type) { + switch(type) { + case DEFAULT: + return defaultOut; + case JSON: + return outJSON; + case XML: + return outXML; + case RAW: + return outRAW; + default: + return defaultOut; + } + } + + public int logType(org.onap.aaf.misc.env.Data.TYPE ot) { + switch(ot) { + case JSON: + return Env.JSON; + default: + return Env.XML; + } + } + + + public RosettaEnv getEnv() { + return env; + } + + + public Data.TYPE getInType() { + return inType; + } + + public Data.TYPE getOutType() { + return outType; + } + + public RosettaDF<T> option(int option) { + defOption = option; + + return this; + } + + /** + * Assigning Root Marshal Object + * + * Will wrap with DocMarshal Object if not already + * + * @param marshal + * @return + */ + public RosettaDF<T> rootMarshal(Marshal<T> marshal) { + if(marshal instanceof DocMarshal) { + this.marshal = marshal; + } else { + this.marshal = DocMarshal.root(marshal); + } + return this; + } + + public void direct(Trans trans, T t, OutputStream os, boolean ... options) throws APIException, IOException { + Out out = getOut(outType); + TimeTaken tt = trans.start(out.logName(),logType(outType)); // determine from Out.. without dependency on Env? + try { + if(marshal==null) { // Unknown marshaller... do working XML marshal/extraction + StringWriter sw = new StringWriter(); + jaxMar.marshal(trans.debug(), t, sw, options); + out.extract(new StringReader(sw.toString()), new OutputStreamWriter(os), inXML,options); + } else { + out.extract(t, new OutputStreamWriter(os), marshal,options); + } + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + } + + public void direct(Trans trans, T t, Writer writer, boolean ... options) throws APIException, IOException { + Out out = getOut(outType); + TimeTaken tt = trans.start(out.logName(),logType(outType)); // determine from Out.. without dependency on Env? + try { + if(marshal==null) { // Unknown marshaller... do working XML marshal/extraction + StringWriter sw = new StringWriter(); + jaxMar.marshal(trans.debug(), t, sw, options); + out.extract(new StringReader(sw.toString()), writer, inXML,options); + } else { + out.extract(t, writer, marshal,options); + } + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + } + + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaData.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaData.java new file mode 100644 index 00000000..446c3c9c --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaData.java @@ -0,0 +1,312 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.env; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Data; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.rosetta.Out; +import org.onap.aaf.misc.rosetta.Parse; +import org.onap.aaf.misc.rosetta.Saved; + +public class RosettaData<T> implements Data<T>{ + private Env trans; + private RosettaDF<T> df; + private Saved saved; + private TYPE inType, outType; + // Note: This is an array of boolean in order to pass into other methods + private boolean options[] = new boolean[] {false, false}; + // Temp Storage of XML. Only when we must use JAXB to read in Objects + private String xml,json; + + // package on purpose + RosettaData(Env env, RosettaDF<T> rosettaDF) { + df = rosettaDF; + saved = new Saved(); // Note: Saved constructs storage as needed... + trans = env; + inType = df.getInType(); + outType = df.getOutType(); // take defaults + } + +// // @Override + public RosettaData<T> in(TYPE rosettaType) { + inType = rosettaType; + return this; + } + +// // @Override + public RosettaData<T> out(TYPE rosettaType) { + outType = rosettaType; + return this; + } + +// // @Override + public RosettaData<T> load(Reader rdr) throws APIException { + Parse<Reader,?> in = df.getIn(inType); + TimeTaken tt = in.start(trans); + try { + saved.extract(rdr, (Writer)null, in); + xml=json=null; + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + return this; + } + + // @Override + public RosettaData<T> load(InputStream is) throws APIException { + Parse<Reader,?> in = df.getIn(inType); + TimeTaken tt = in.start(trans); + try { + saved.extract(new InputStreamReader(is), (Writer)null, in); + xml=json=null; + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + return this; + } + + // @Override + public RosettaData<T> load(String str) throws APIException { + Parse<Reader,?> in = df.getIn(inType); + TimeTaken tt = in.start(trans); + try { + saved.extract(new StringReader(str), (Writer)null, in); + switch(inType) { + case XML: + xml = str; + break; + case JSON: + json = str; + break; + default: + + } + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + return this; + } + + // @Override + public RosettaData<T> load(T t) throws APIException { + Parse<?,?> in = df.getIn(inType); + TimeTaken tt = in.start(trans); + try { + if(df.marshal==null) { // Unknown marshaller... do working XML marshal/extraction + StringWriter sw = new StringWriter(); + df.jaxMar.marshal(trans.debug(), t, sw, options); + saved.extract(new StringReader(xml = sw.toString()), (Writer)null, df.inXML); + } else { + saved.extract(t, (Writer)null, df.marshal); + } + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + return this; + } + + public Saved getEvents() { + return saved; + } + + // @Override + public T asObject() throws APIException { + Out out = df.getOut(TYPE.XML); + TimeTaken tt = trans.start(out.logName(),df.logType(outType)); // determine from Out.. without dependency on Env? + try { + //TODO Replace JAXB with Direct Object method!!! + StringWriter sw = new StringWriter(); + out.extract(null, sw, saved); + return df.jaxUmar.unmarshal(trans.debug(), sw.toString()); + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + } + + // @Override + public String asString() throws APIException { + Out out = df.getOut(outType); + TimeTaken tt = trans.start(out.logName(),df.logType(outType)); // determine from Out.. without dependency on Env? + try { + if(outType==TYPE.XML) { + if(xml==null) { + StringWriter sw = new StringWriter(); + out.extract(null, sw, saved, options); + xml = sw.toString(); + } + return xml; + } else { // is JSON + if(json==null) { + StringWriter sw = new StringWriter(); + out.extract(null, sw, saved, options); + json = sw.toString(); + } + return json; + } + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + } + + + // @Override + public RosettaData<T> to(OutputStream os) throws APIException, IOException { + Out out = df.getOut(outType); + TimeTaken tt = trans.start(out.logName(),df.logType(outType)); // determine from Out.. without dependency on Env? + try { + if(outType==TYPE.XML && xml!=null) { + os.write(xml.getBytes()); + } else if(outType==TYPE.JSON && json!=null) { + os.write(json.getBytes()); + } else { + out.extract(null, os, saved, options); + } + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + return this; + } + + // @Override + public RosettaData<T> to(Writer writer) throws APIException, IOException { + Out out = df.getOut(outType); + TimeTaken tt = trans.start(out.logName(),df.logType(outType)); // determine from Out.. without dependency on Env? + try { + if(outType==TYPE.XML && xml!=null) { + writer.append(xml); + } else if(outType==TYPE.JSON && json!=null) { + writer.append(json); + } else { + out.extract(null, writer, saved, options); + } + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + return this; + } + + // @Override + public Class<T> getTypeClass() { + return df.getTypeClass(); + } + + private static final boolean[] emptyOption = new boolean[0]; + + public void direct(InputStream is, OutputStream os) throws APIException, IOException { + direct(is,os,emptyOption); + } + + public void direct(Reader reader, Writer writer, boolean ... options) throws APIException, IOException { + Parse<Reader,?> in = df.getIn(inType); + Out out = df.getOut(outType); + TimeTaken tt = trans.start(out.logName(),df.logType(outType)); // determine from Out.. without dependency on Env? + try { + out.extract(reader, writer, in,options); + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + } + + public void direct(T t, Writer writer, boolean ... options) throws APIException, IOException { + Out out = df.getOut(outType); + TimeTaken tt = trans.start(out.logName(),df.logType(outType)); // determine from Out.. without dependency on Env? + try { + if(df.marshal==null) { // Unknown marshaller... do working XML marshal/extraction + StringWriter sw = new StringWriter(); + df.jaxMar.marshal(trans.debug(), t, sw, options); + out.extract(new StringReader(xml = sw.toString()), writer, df.inXML,options); + } else { + out.extract(t, writer, df.marshal,options); + } + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + } + + public void direct(T t, OutputStream os, boolean ... options) throws APIException, IOException { + Out out = df.getOut(outType); + TimeTaken tt = trans.start(out.logName(),df.logType(outType)); // determine from Out.. without dependency on Env? + try { + if(df.marshal==null) { // Unknown marshaller... do working XML marshal/extraction + if(outType.equals(TYPE.XML)) { + df.jaxMar.marshal(trans.debug(), t, os, options); + } else { + StringWriter sw = new StringWriter(); + df.jaxMar.marshal(trans.debug(), t, sw, options); + out.extract(new StringReader(xml = sw.toString()), new OutputStreamWriter(os), df.inXML,options); + } + } else { + out.extract(t, new OutputStreamWriter(os), df.marshal,options); + } + + } catch (Exception e) { + throw new APIException(e); + } finally { + tt.done(); + } + } + + + public void direct(InputStream is, OutputStream os, boolean ... options) throws APIException, IOException { + direct(new InputStreamReader(is),new OutputStreamWriter(os), options); + } + + // // @Override + public RosettaData<T> option(int option) { + options[0] = (option&Data.PRETTY)==Data.PRETTY; + options[1] = (option&Data.FRAGMENT)==Data.FRAGMENT; + return this; + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaEnv.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaEnv.java new file mode 100644 index 00000000..05c75b7e --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/env/RosettaEnv.java @@ -0,0 +1,89 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.env; + +import java.applet.Applet; +import java.util.Properties; + +import javax.xml.namespace.QName; +import javax.xml.validation.Schema; + +import org.onap.aaf.misc.env.APIException; + +/** + * An essential Implementation of Env, which will fully function, without any sort + * of configuration. + * + * Use as a basis for Group level Env, just overriding where needed. + * @author Jonathan + * + */ +public class RosettaEnv extends org.onap.aaf.misc.env.impl.BasicEnv { + + public RosettaEnv() { + super(); + } + + public RosettaEnv(Applet applet, String... tags) { + super(applet, tags); + } + + public RosettaEnv(String[] args) { + super(args); + } + + public RosettaEnv(String tag, String[] args) { + super(tag, args); + } + + public RosettaEnv(String tag, Properties props) { + super(tag, props); + } + + public RosettaEnv(Properties props) { + super(props); + } + + @SuppressWarnings("unchecked") + @Override + public <T> RosettaDF<T> newDataFactory(Class<?>... classes) throws APIException { + return new RosettaDF<T>(this, null, null, (Class<T>)classes[0]); + } + + @SuppressWarnings("unchecked") + @Override + public <T> RosettaDF<T> newDataFactory(Schema schema, Class<?>... classes) throws APIException { + return new RosettaDF<T>(this, schema, null, (Class<T>)classes[0]); + } + + @SuppressWarnings("unchecked") + @Override + public<T> RosettaDF<T> newDataFactory(QName qName, Class<?> ... classes) throws APIException { + return new RosettaDF<T>(this, null, qName.getNamespaceURI(),(Class<T>)classes[0]); + } + + @SuppressWarnings("unchecked") + @Override + public<T> RosettaDF<T> newDataFactory(Schema schema, QName qName, Class<?> ... classes) throws APIException { + return new RosettaDF<T>(this, schema,qName.getNamespaceURI(),(Class<T>)classes[0]); + } +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/DataWriter.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/DataWriter.java new file mode 100644 index 00000000..1655928d --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/DataWriter.java @@ -0,0 +1,139 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +import javax.xml.datatype.XMLGregorianCalendar; + +import org.onap.aaf.misc.env.util.Chrono; + +/** + * We make these objects instead of static functions so they can be passed into + * FieldArray. + * + * @author Jonathan + * + * @param <T> + */ +public abstract class DataWriter<T> { + public abstract boolean write(T t, StringBuilder sb); + + public final static DataWriter<String> STRING = new DataWriter<String>() { + @Override + public boolean write(String s, StringBuilder sb) { + sb.append(s); + return true; + } + }; + + public final static DataWriter<Integer> INTEGER = new DataWriter<Integer>() { + @Override + public boolean write(Integer i, StringBuilder sb) { + sb.append(i); + return false; + } + }; + + public final static DataWriter<Long> LONG = new DataWriter<Long>() { + @Override + public boolean write(Long t, StringBuilder sb) { + sb.append(t); + return false; + } + }; + + public final static DataWriter<Byte> BYTE = new DataWriter<Byte>() { + @Override + public boolean write(Byte t, StringBuilder sb) { + sb.append(t); + return false; + } + }; + + public final static DataWriter<Character> CHAR = new DataWriter<Character>() { + @Override + public boolean write(Character t, StringBuilder sb) { + sb.append(t); + return true; + } + }; + + public final static DataWriter<Boolean> BOOL = new DataWriter<Boolean>() { + @Override + public boolean write(Boolean t, StringBuilder sb) { + sb.append(t); + return true; + } + }; + + + /* + public final static DataWriter<byte[]> BYTE_ARRAY = new DataWriter<byte[]>() { + @Override + public boolean write(byte[] ba, StringBuilder sb) { + ByteArrayInputStream bais = new ByteArrayInputStream(ba); + StringBuilderOutputStream sbos = new StringBuilderOutputStream(sb); +// try { + //TODO find Base64 +// Symm.base64noSplit().encode(bais, sbos); +// } catch (IOException e) { +// // leave blank +// } + return true; + } + + }; + */ + + public final static DataWriter<XMLGregorianCalendar> DATE = new DataWriter<XMLGregorianCalendar>() { + @Override + public boolean write(XMLGregorianCalendar t, StringBuilder sb) { + sb.append(Chrono.dateOnlyStamp(t)); + return true; + } + }; + + public final static DataWriter<XMLGregorianCalendar> DATE_TIME = new DataWriter<XMLGregorianCalendar>() { + @Override + public boolean write(XMLGregorianCalendar t, StringBuilder sb) { + sb.append(Chrono.dateTime(t)); + return true; + } + }; + + private static final char[] chars="0123456789ABCDEF".toCharArray(); + public final static DataWriter<byte[]> HEX_BINARY = new DataWriter<byte[]>() { + @Override + public boolean write(byte[] ba, StringBuilder sb) { + // FYI, doing this because don't want intermediate + // String in "HexString" or the processing in + // "String.format" + //sb.append("0x"); + for(int i=0;i<ba.length;++i) { + byte b = ba[i]; + sb.append(chars[((b&0xF0)>>4)]); + sb.append(chars[b&0xF]); + } + return true; + } + }; + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/DocMarshal.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/DocMarshal.java new file mode 100644 index 00000000..5249a17a --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/DocMarshal.java @@ -0,0 +1,82 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +import java.util.Iterator; + +import org.onap.aaf.misc.rosetta.Ladder; +import org.onap.aaf.misc.rosetta.Marshal; +import org.onap.aaf.misc.rosetta.ParseException; +import org.onap.aaf.misc.rosetta.Parsed; + +public class DocMarshal<T> extends Marshal<T> { + private Marshal<T> root; + + public DocMarshal(Marshal<T> root) { + this.root = root; + } + + @Override + public Parsed<State> parse(T t, Parsed<State> parsed) throws ParseException { + Ladder<Iterator<?>> ladder = parsed.state.ladder; + Iterator<?> iter = ladder.peek(); + if(iter==null) { + ladder.push(PENDING_ITERATOR); + parsed.event = START_DOC; + } else if (DONE_ITERATOR.equals(iter)) { + } else { + ladder.ascend(); // look at field info + Iterator<?> currFieldIter = ladder.peek(); + if(!DONE_ITERATOR.equals(currFieldIter)){ + parsed = root.parse(t, parsed); + } + ladder.descend(); + if(DONE_ITERATOR.equals(currFieldIter) || parsed.event==NONE) { + parsed.event = END_DOC; + ladder.push(DONE_ITERATOR); + } + } + return parsed; // if unchanged, then it will end process + + } + + public static final Iterator<Void> PENDING_ITERATOR = new Iterator<Void>() { + @Override + public boolean hasNext() { + return false; + } + + @Override + public Void next() { + return null; + } + + @Override + public void remove() { + } + }; + + public static<T> DocMarshal<T> root(Marshal<T> m) { + return (DocMarshal<T>)new DocMarshal<T>(m); + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldArray.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldArray.java new file mode 100644 index 00000000..3006f897 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldArray.java @@ -0,0 +1,92 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +import java.util.Iterator; +import java.util.List; + +import org.onap.aaf.misc.rosetta.Ladder; +import org.onap.aaf.misc.rosetta.Marshal; +import org.onap.aaf.misc.rosetta.ParseException; +import org.onap.aaf.misc.rosetta.Parsed; + + +public abstract class FieldArray<T,S> extends Marshal<T> { + private DataWriter<S> dataWriter; + private String name; + + public FieldArray(String name, DataWriter<S> dw) { + this.name = name; + dataWriter = dw; + } + + @SuppressWarnings("unchecked") + @Override + public Parsed<State> parse(T t, Parsed<State> parsed) throws ParseException { + Ladder<Iterator<?>> ladder = parsed.state.ladder; + Iterator<?> iter = ladder.peek(); + if(iter==null) { + List<S> list = data(t); + if(list.isEmpty() && parsed.state.smallest) { + ladder.push(DONE_ITERATOR); + } else { + ladder.push(new ListIterator<S>(list)); + parsed.event = START_ARRAY; + parsed.name = name; + } + } else if (DONE_ITERATOR.equals(iter)) { + } else { + ladder.ascend(); // look at field info + Iterator<?> memIter = ladder.peek(); + ListIterator<S> mems = (ListIterator<S>)iter; + S mem; + if(memIter==null) { + mem=mems.next(); + } else if(!DONE_ITERATOR.equals(memIter)) { + mem=mems.peek(); + } else if(iter.hasNext()) { + mem=null; + ladder.push(null); + } else { + mem=null; + } + + if(mem!=null) { + parsed.isString=dataWriter.write(mem, parsed.sb); + parsed.event = NEXT; + } + ladder.descend(); + if(mem==null) { + if(iter.hasNext()) { + parsed.event = NEXT; + } else { + parsed.event = END_ARRAY; + ladder.push(DONE_ITERATOR); + } + } + } + return parsed; // if unchanged, then it will end process + } + + protected abstract List<S> data(T t); + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldBlob.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldBlob.java new file mode 100644 index 00000000..1de14e82 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldBlob.java @@ -0,0 +1,38 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +public abstract class FieldBlob<T> extends FieldMarshal<T>{ + public FieldBlob(String name) { + super(name); + } + + protected abstract byte[] data(T t); + + @Override + protected boolean data(T t, StringBuilder sb) { + return false; + // unimplemented + //return DataWriter.BYTE_ARRAY.write(data(t),sb); + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldDate.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldDate.java new file mode 100644 index 00000000..b3632a14 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldDate.java @@ -0,0 +1,37 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +import javax.xml.datatype.XMLGregorianCalendar; + +public abstract class FieldDate<T> extends FieldMarshal<T> { + public FieldDate(String name) { + super(name); + } + + @Override + final protected boolean data(T t, StringBuilder sb) { + return DataWriter.DATE.write(data(t), sb); + } + + protected abstract XMLGregorianCalendar data(T t); +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldDateTime.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldDateTime.java new file mode 100644 index 00000000..8aa29829 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldDateTime.java @@ -0,0 +1,37 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +import javax.xml.datatype.XMLGregorianCalendar; + +public abstract class FieldDateTime<T> extends FieldMarshal<T> { + public FieldDateTime(String name) { + super(name); + } + + @Override + final protected boolean data(T t, StringBuilder sb) { + return DataWriter.DATE_TIME.write(data(t), sb); + } + + protected abstract XMLGregorianCalendar data(T t); +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldHexBinary.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldHexBinary.java new file mode 100644 index 00000000..589d0920 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldHexBinary.java @@ -0,0 +1,35 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +public abstract class FieldHexBinary<T> extends FieldMarshal<T>{ + public FieldHexBinary(String name) { + super(name); + } + + protected abstract byte[] data(T t); + + @Override + protected boolean data(T t, StringBuilder sb) { + return DataWriter.HEX_BINARY.write(data(t), sb); + } +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldMarshal.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldMarshal.java new file mode 100644 index 00000000..cb8b6557 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldMarshal.java @@ -0,0 +1,59 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + + +import org.onap.aaf.misc.rosetta.Marshal; +import org.onap.aaf.misc.rosetta.Parse; +import org.onap.aaf.misc.rosetta.Parsed; + +public abstract class FieldMarshal<T> extends Marshal<T> { + private String name; + + public FieldMarshal(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public Parsed<State> parse(T t, Parsed<State> parsed) { + parsed.state.ladder.push(DONE_ITERATOR); + parsed.event = Parse.NEXT; + parsed.name = name; + parsed.isString = data(t,parsed.sb); + return parsed; + } + + /** + * Write Value to StringBuilder + * Return true if value looks like a String + * false if it is Numeric + * @param t + * @param sb + * @return + */ + protected abstract boolean data(T t, StringBuilder sb); + +}
\ No newline at end of file diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldNumeric.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldNumeric.java new file mode 100644 index 00000000..aac9ac69 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldNumeric.java @@ -0,0 +1,36 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +public abstract class FieldNumeric<N,T> extends FieldMarshal<T> { + public FieldNumeric(String name) { + super(name); + } + + @Override + final protected boolean data(T t, StringBuilder sb) { + sb.append(data(t)); + return false; + } + + protected abstract N data(T t); +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldString.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldString.java new file mode 100644 index 00000000..2337c3c9 --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/FieldString.java @@ -0,0 +1,36 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +public abstract class FieldString<T> extends FieldMarshal<T> { + public FieldString(String name) { + super(name); + } + + protected abstract String data(T t); + + @Override + final protected boolean data(T t, StringBuilder sb) { + return DataWriter.STRING.write(data(t), sb); + } + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ListIterator.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ListIterator.java new file mode 100644 index 00000000..6045141d --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ListIterator.java @@ -0,0 +1,59 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +import java.util.Iterator; +import java.util.List; + +/** + * Need an Iterator that can peek the current value without changing + * @author Jonathan + * + * @param <T> + */ +final class ListIterator<T> implements Iterator<T> { + private T curr; + private Iterator<T> delg; + public ListIterator(List<T> list) { + curr = null; + delg = list.iterator(); + } + @Override + public boolean hasNext() { + return delg.hasNext(); + } + + @Override + public T next() { + return curr = delg.hasNext()?delg.next():null; + } + + public T peek() { + return curr==null?next():curr; + } + + @Override + public void remove() { + delg.remove(); + } + +}
\ No newline at end of file diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ObjArray.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ObjArray.java new file mode 100644 index 00000000..3d7d1b4e --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ObjArray.java @@ -0,0 +1,90 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +import java.util.Iterator; +import java.util.List; + +import org.onap.aaf.misc.rosetta.Ladder; +import org.onap.aaf.misc.rosetta.Marshal; +import org.onap.aaf.misc.rosetta.ParseException; +import org.onap.aaf.misc.rosetta.Parsed; + + +public abstract class ObjArray<T,S> extends Marshal<T> { + private String name; + private Marshal<S> subMarshaller; + + public ObjArray(String name, Marshal<S> subMarshaller) { + this.name = name; + this.subMarshaller = subMarshaller; + } + + @SuppressWarnings("unchecked") + @Override + public Parsed<State> parse(T t, Parsed<State> parsed) throws ParseException { + Ladder<Iterator<?>> ladder = parsed.state.ladder; + Iterator<?> iter = ladder.peek(); + if(iter==null) { + List<S> list = data(t); + if(list.isEmpty() && parsed.state.smallest) { + ladder.push(DONE_ITERATOR); + } else { + ladder.push(new ListIterator<S>(list)); + parsed.event = START_ARRAY; + parsed.name = name; + } + } else if (DONE_ITERATOR.equals(iter)) { + } else { + ladder.ascend(); // look at field info + Iterator<?> memIter = ladder.peek(); + ListIterator<S> mems = (ListIterator<S>)iter; + S mem; + if(memIter==null) { + mem=mems.next(); + } else if(!DONE_ITERATOR.equals(memIter)) { + mem=mems.peek(); + } else if(iter.hasNext()) { + mem=null; + ladder.push(null); + } else { + mem=null; + } + + if(mem!=null) + parsed = subMarshaller.parse(mem, parsed); + ladder.descend(); + if(mem==null) { + if(iter.hasNext()) { + parsed.event = NEXT; + } else { + parsed.event = END_ARRAY; + ladder.push(DONE_ITERATOR); + } + } + } + return parsed; // if unchanged, then it will end process + } + + protected abstract List<S> data(T t); + +} diff --git a/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ObjMarshal.java b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ObjMarshal.java new file mode 100644 index 00000000..eaa7a74a --- /dev/null +++ b/misc/rosetta/src/main/java/org/onap/aaf/misc/rosetta/marshal/ObjMarshal.java @@ -0,0 +1,128 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ + +package org.onap.aaf.misc.rosetta.marshal; + +import java.util.Iterator; + +import org.onap.aaf.misc.rosetta.Ladder; +import org.onap.aaf.misc.rosetta.Marshal; +import org.onap.aaf.misc.rosetta.ParseException; +import org.onap.aaf.misc.rosetta.Parsed; + +/** + * Object Marshal + * Assumes has Fields and other Objects + * s + * @author Jonathan + * + * @param <T> + */ +public abstract class ObjMarshal<T> extends Marshal<T> { + // Note: Not Using List or ArrayList, because there is no "Peek" concept in their iterator. + private Marshal<T>[] pml; + private int end=0; + + /** + * @param pm + */ + @SuppressWarnings("unchecked") + protected void add(Marshal<T> pm) { + if(pml==null) { + pml = new Marshal[Ladder.DEFAULT_INIT_SIZE]; + } else if(end>pml.length) { + Object temp[] = pml; + pml = new Marshal[pml.length+Ladder.DEFAULT_INIT_SIZE]; + System.arraycopy(temp, 0, pml, 0, pml.length); + } + pml[end]=pm; + ++end; + } + + /* (non-Javadoc) + * @see org.onap.aaf.misc.rosetta.Parse#parse(java.lang.Object, org.onap.aaf.misc.rosetta.Parsed) + */ + @SuppressWarnings("unchecked") + @Override + public Parsed<State> parse(T in, Parsed<State> parsed) throws ParseException { + Ladder<Iterator<?>> ladder = parsed.state.ladder; + Iterator<Marshal<T>> iter = (Iterator<Marshal<T>>)ladder.peek(); + if(iter==null) { + if(pml.length>0) { + ladder.push(new FieldsIterator()); + parsed.event = START_OBJ; + } else { + ladder.push(DONE_ITERATOR); + } + } else if (DONE_ITERATOR.equals(iter)) { + } else { + FieldsIterator fields = (FieldsIterator)iter; + ladder.ascend(); // look at field info + Iterator<?> currFieldIter = ladder.peek(); + Marshal<T> marshal; + if(currFieldIter==null) { + marshal=fields.next(); + } else if(!DONE_ITERATOR.equals(currFieldIter)) { + marshal=fields.peek(); + if(marshal==null && fields.hasNext())marshal=fields.next(); + } else if(fields.hasNext()) { + marshal=fields.next(); + ladder.push(null); + } else { + marshal=null; + } + + if(marshal!=null) + parsed = marshal.parse(in, parsed); + ladder.descend(); + if(marshal==null || parsed.event==NONE) { + parsed.event = END_OBJ; + ladder.push(DONE_ITERATOR); + } + } + return parsed; // if unchanged, then it will end process + } + + private class FieldsIterator implements Iterator<Marshal<T>> { + private int idx = -1; + + @Override + public boolean hasNext() { + return idx<end; + } + + @Override + public Marshal<T> next() { + return pml[++idx]; + } + + public Marshal<T> peek() { + return idx<0?null:pml[idx]; + } + + @Override + public void remove() { + pml[idx]=null; + } + + } + +} diff --git a/misc/rosetta/src/main/xsd/inherit.xsd b/misc/rosetta/src/main/xsd/inherit.xsd new file mode 100644 index 00000000..e0a33fb4 --- /dev/null +++ b/misc/rosetta/src/main/xsd/inherit.xsd @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * +--> +<xs:schema elementFormDefault="qualified" + targetNamespace="urn:inherit" + xmlns="urn:inherit" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + > + + <xs:complexType name="baseType"> + <xs:sequence> + <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1" /> + <xs:element name="num" type="xs:short" minOccurs="0" maxOccurs="1" /> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="derivedA"> + <xs:annotation> + <xs:documentation>Select one of the items</xs:documentation> + </xs:annotation> + <xs:complexContent> + <xs:extension base="baseType"> + <xs:sequence> + <xs:element name="shortName" type="xs:string" minOccurs="0" maxOccurs="1" /> + <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + + <xs:element name="root"> + <xs:complexType> + <xs:sequence> + <xs:element name="base" type="baseType" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> + </xs:element> + +</xs:schema>
\ No newline at end of file diff --git a/misc/rosetta/src/main/xsd/s.xsd b/misc/rosetta/src/main/xsd/s.xsd new file mode 100644 index 00000000..b4d137e8 --- /dev/null +++ b/misc/rosetta/src/main/xsd/s.xsd @@ -0,0 +1,64 @@ +<!-- + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * +--> +<xs:schema elementFormDefault="qualified" + targetNamespace="urn:s:xsd" + xmlns:s="urn:s:xsd" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + > + + <xs:element name="SampleData"> + <xs:complexType> + <xs:sequence> + <xs:element name="id" type="xs:string" minOccurs="1" maxOccurs="1" /> + <xs:element name="date" type="xs:long"/> + <xs:element name="item" type="xs:string" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> + </xs:element> + + <xs:element name="LargerData"> + <xs:complexType> + <xs:sequence> + <xs:element ref="s:SampleData" minOccurs="1" maxOccurs="unbounded"/> + <xs:element name="fluff" type="xs:string"/> + </xs:sequence> + </xs:complexType> + </xs:element> + + <xs:element name="LargerDatas"> + <xs:complexType> + <xs:sequence> + <xs:element ref="s:LargerData" minOccurs="1" maxOccurs = "unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + + + <xs:element name="Multi"> + <xs:complexType> + <xs:sequence> + <xs:element name="f1" type="xs:string" minOccurs="0" maxOccurs = "unbounded"/> + <xs:element name="f2" type="xs:string" minOccurs="0" maxOccurs = "unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> + +</xs:schema>
\ No newline at end of file diff --git a/misc/rosetta/src/main/xsd/types.xsd b/misc/rosetta/src/main/xsd/types.xsd new file mode 100644 index 00000000..5533964b --- /dev/null +++ b/misc/rosetta/src/main/xsd/types.xsd @@ -0,0 +1,46 @@ +<!-- + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * +--> +<xs:schema elementFormDefault="qualified" + targetNamespace="urn:types:xsd" + xmlns:s="urn:types:xsd" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + > + <xs:element name="multi"> + <xs:complexType> + <xs:sequence> + <xs:element name="single" minOccurs="0" maxOccurs="unbounded"> + <xs:complexType> + <xs:sequence> + <xs:element name="str" type="xs:string" minOccurs="1" maxOccurs="1" /> + <xs:element name="int" type="xs:int" minOccurs="1" maxOccurs="1" /> + <xs:element name="long" type="xs:long" minOccurs="1" maxOccurs="1" /> + <xs:element name="date" type="xs:date" minOccurs="1" maxOccurs="1" /> + <xs:element name="datetime" type="xs:dateTime" minOccurs="1" maxOccurs="1" /> + <xs:element name="binary" type="xs:hexBinary" minOccurs="1" maxOccurs="1" /> + <xs:element name="array" type="xs:string" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + +</xs:schema>
\ No newline at end of file |