de.extra.xtt.util.ExtraTailoringImpl Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package de.extra.xtt.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Locator;
import com.sun.xml.xsom.XSComplexType;
import com.sun.xml.xsom.XSElementDecl;
import com.sun.xml.xsom.XSSchemaSet;
import com.sun.xml.xsom.XSSimpleType;
import com.sun.xml.xsom.XSType;
import de.extra.xtt.gui.model.ProfilingTreeNode;
import de.extra.xtt.util.schema.MySchemaWriter;
import de.extra.xtt.util.schema.SchemaElement;
import de.extra.xtt.util.tools.Configurator;
import de.extra.xtt.util.tools.XsdXmlHelper;
/**
* Implementierung für die Erzeugung eines spezifischen eXTra-Schemas.
*
* @author Beier
*/
public class ExtraTailoringImpl implements ExtraTailoring {
private final Configurator configurator;
/**
* Konstruktur mit der Zuweisung eines initialisierten Configurator-Objekts.
*
* @param configurator
* Configurator zum Zugriff u.a. auf Properties
*/
public ExtraTailoringImpl(Configurator configurator) {
this.configurator = configurator;
}
/**
* {@inheritdoc}
*/
@Override
public Map erzeugeProfiliertesExtraSchema(
XSSchemaSet ssQuellSchema, Document profilXml,
String bezeichnungKurzVerfahren) throws ExtraTailoringException {
if ((ssQuellSchema != null) && (profilXml != null)
&& (bezeichnungKurzVerfahren != null)) {
try {
MySchemaWriter schemaWriter = new MySchemaWriter("xs",
"http://www.w3.org/2001/XMLSchema", configurator, 1);
// Element-Knoten aus der Profilierungsdatei abarbeiten
List xsElementsToInsert = new LinkedList();
List xsElementsInserted = new LinkedList();
NodeList xmlNodesElementProf = XsdXmlHelper.xpathSuche(
"//element", profilXml);
if (xmlNodesElementProf.getLength() > 0) {
for (int i = 0; i < xmlNodesElementProf.getLength(); i++) {
erzeugeSchemaTypUndElementFuerProfElement(
xmlNodesElementProf.item(i), ssQuellSchema,
xsElementsToInsert, xsElementsInserted,
schemaWriter);
}
} else {
throw new ExtraTailoringException(
"Profilkonfiguration enth�lt keine Elemente.");
}
// Zus�tzlich referenzierte Elemente behandeln, die nicht
// bereits in der Liste der noch zu hinzuf�genden Elementen
// stehen
printRefElements(schemaWriter, ssQuellSchema,
xsElementsToInsert, xsElementsInserted);
// Verwendete Typen schreiben
schemaWriter.printReferencedTypes(profilXml);
// Am Ende Elemente schreiben
for (XSElementDecl currElement : xsElementsToInsert) {
// entsprechenden Knoten in Profilkonfiguration suchen (f�r
// evtl. Anmerkungen)
String strNameCurrElement = configurator
.getPropertyNamespace(currElement
.getTargetNamespace())
+ ":" + currElement.getName();
Node currElementNode = XsdXmlHelper.xpathSuche(
"//element[name/text()='" + strNameCurrElement
+ "']", profilXml).item(0);
schemaWriter.elementDecl(currElement, "", null,
currElementNode, "");
}
// Schemadateien schreiben
Map xsdDocs = new HashMap();
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
docFactory.setNamespaceAware(true);
DocumentBuilder parser = docFactory.newDocumentBuilder();
Map nsWriter = schemaWriter.getNsWriter();
Map nsOutputStream = schemaWriter
.getNsOutputStream();
// Einzelne Namespace-Witer abarbeiten
for (Map.Entry currEntry : nsWriter.entrySet()) {
String currNsPrefix = currEntry.getKey();
String currNsUrl = configurator
.getPropertyNamespace(currNsPrefix);
List usedNamespaces = schemaWriter
.getNsUsedNamespaces().get(currNsPrefix);
// Schema-Header schreiben
ByteArrayOutputStream outStreamCurrDocXsd = new ByteArrayOutputStream();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
OutputStreamWriter swHeader = new OutputStreamWriter(
outStream, "UTF8");
swHeader.write("\r\n");
swHeader.write("\r\n");
// Import-Anweisungen erzeugen
for (String strNsPrefixUsed : usedNamespaces) {
if (!strNsPrefixUsed.equals("xs")) {
String currNsUrlUsed = configurator
.getPropertyNamespace(strNsPrefixUsed);
String currDateinameImport = configurator
.getDateinameFuerSchema(
bezeichnungKurzVerfahren,
strNsPrefixUsed);
swHeader.write(" \r\n");
}
}
swHeader.flush();
// Header schreiben
outStream.writeTo(outStreamCurrDocXsd);
// Hauptdaten schreiben
nsOutputStream.get(currEntry.getKey()).writeTo(
outStreamCurrDocXsd);
// Ende schreiben
outStream.reset();
swHeader.write(" ");
swHeader.flush();
outStream.writeTo(outStreamCurrDocXsd);
// XSD-Dokument aus Stream erzeugen
Document currDocSchemaProf = parser
.parse(new ByteArrayInputStream(outStreamCurrDocXsd
.toByteArray()));
xsdDocs.put(currNsPrefix, currDocSchemaProf);
}
return xsdDocs;
} catch (Exception e) {
throw new ExtraTailoringException(
"Fehler beim Erzeugen des profilierten Schemas.", e);
}
} else {
throw new ExtraTailoringException(
"�bergebenes Quell-Schema, Profildokument oder Bezeichnung ung�ltig (NULL).");
}
}
/**
* {@inheritdoc}
*/
@Override
public Document erzeugeProfilkonfiguration(
Configurator.SchemaType schemaType, ProfilingTreeNode rootNodeMain,
ProfilingTreeNode rootNodeRef, String targetNamespace,
String bezVerfahrenKurz, String bezVerfahren)
throws ExtraTailoringException {
if (configurator != null) {
try {
// Dokument mit Wurzelknoten erzeugen
Document docXml = erzeugeLeeresDokument("profil-konfiguration");
Element root = (Element) docXml.getFirstChild();
// Attribute setzen
root.setAttribute("tnsUrl", targetNamespace);
root.setAttribute("bezKurzVerfahren", bezVerfahrenKurz);
root.setAttribute("bezVerfahren", bezVerfahren);
// Baum durchlaufen und f�r jedes Element mit Kindknoten
// element-Knoten erzeugen
List elementsAdded = new LinkedList();
insertNodeProfXml(rootNodeMain, rootNodeRef, docXml,
elementsAdded);
return docXml;
} catch (Exception e) {
throw new ExtraTailoringException(
"Fehler beim Erzeugen des Profildokuments.", e);
}
} else {
throw new ExtraTailoringException("Configurator nicht vorhanden.");
}
}
/**
* Erzeugt ein zum �bergebenen ProfilingTreeNode-Objekt passendes
* element-XML-Element mit den entsprechenden Kind-Elementen und h�ngt es
* dan das �bergebene XML-Dokument an.
*
* @param currNode
* Zu bearbeitender ProfilingTreeNode
* @param rootNodeRef
* Wruzelelemet des Bausm mit allen referenzierten Elementen
* @param docXml
* Profilkonfiguration, in die das neue Element eingef�gt wird
* @param elementsAdded
* Liste aller bereits hinzugef�gter Elemente
*/
private void insertNodeProfXml(ProfilingTreeNode currNode,
ProfilingTreeNode rootNodeRef, Document docXml,
List elementsAdded) {
SchemaElement currSchemaElement = currNode.getSchemaElement();
String bezeichnungWithNamespacePrefix = currSchemaElement
.getNameWithPrefix();
// Falls schon hinzugef�gt, dann nicht erneut Knoten erzeugen
if (!elementsAdded.contains(bezeichnungWithNamespacePrefix)) {
// 'element'
Node nodeElement = docXml.createElement("element");
// Kind 'name'
Node nodeName = docXml.createElement("name");
nodeName.setTextContent(bezeichnungWithNamespacePrefix);
nodeElement.appendChild(nodeName);
// zur Liste der bereits hinzugef�gten Elemente hinzuf�gen
elementsAdded.add(bezeichnungWithNamespacePrefix);
// Kind 'anmerkung'
String anmerkungAllgText = configurator
.getAnmerkungAllgemein(currNode);
if (anmerkungAllgText.length() > 0) {
Node nodeAnmerkung = docXml.createElement("anmerkung");
nodeAnmerkung.setTextContent(anmerkungAllgText);
nodeElement.appendChild(nodeAnmerkung);
}
// element hinzuf�gen
docXml.getFirstChild().appendChild(nodeElement);
// Kinder 'kind'
Enumeration enumChilds = null;
if (currNode.getChildCount() > 0) {
// eigene Kinder behandeln
enumChilds = currNode.children();
} else if (rootNodeRef != null) {
// Pr�fen, ob in den referenzierten Knoten Elemente f�r dieses
// aktuelle Element vorhanden sind
ProfilingTreeNode nodeRef = rootNodeRef
.getChildWithSameSchemaElement(currSchemaElement);
if ((nodeRef != null) && (nodeRef.getChildCount() > 0)) {
// Kindern vom referenzierten Knoten behandeln
enumChilds = nodeRef.children();
}
}
// Kind-Elemente erzeugen
if (enumChilds != null) {
for (Enumeration e = enumChilds; e
.hasMoreElements();) {
ProfilingTreeNode currNodeChild = e.nextElement();
if (currNodeChild.isChecked()) {
Element nodeKind = docXml.createElement("kind");
// min- und maxOccurs
if (currNodeChild.isMinOccursChangeable()
&& (currNodeChild.getMinOccursUser() != currNodeChild
.getMinOccursDefault())) {
nodeKind.setAttribute("minOccurs", ""
+ currNodeChild.getMinOccursUser());
}
if (currNodeChild.isMaxOccursChangeable()
&& (currNodeChild.getMaxOccursUser() != currNodeChild
.getMaxOccursDefault())) {
nodeKind.setAttribute("maxOccurs", ""
+ currNodeChild.getMaxOccursUser());
}
// Anmerkung zur Verwendnug
String anmerkungVerwendung = configurator
.getAnmerkungVerwendung(currNodeChild);
if (anmerkungVerwendung.length() > 0) {
nodeKind.setAttribute("anmerkung",
anmerkungVerwendung);
}
nodeKind.setTextContent(currNodeChild
.getSchemaElement().getNameWithPrefix());
nodeElement.appendChild(nodeKind);
// rekursiver Aufruf
insertNodeProfXml(currNodeChild, rootNodeRef, docXml,
elementsAdded);
}
}
}
}
}
/**
* F�r den angebenen XML-Knoten aus der Profilkonfiguration wird ein
* SchemaElement erzeugt und im Quellschema das passende Element gesucht.
* F�r dieses Element aus dem Quellschema wird dann der Abschnitt f�r das
* profilierte Schema mittels SchemaWriter erzeugt.
*
* @param xmlNodeElement
* Aktueller XMl-Knoten aus der Profilkonfiguration
* @param ssQuellSchema
* Quellschema mit allen Elementen und Typen
* @param xsElementsToInsert
* Liste aller Elemente, die im aktuellen Profil verwendet
* werden; diese werden erst gesammelt und nach den Typen
* geschrieben.
* @param xsElementsInserted
* Liste aller Elemente, die bereits hinzugef�gt wurden
* @param schemaWriter
* Objekt zum Erzeugen des XML-Textes f�r die zu erzeugende
* Schemadatei
* @throws XPathExpressionException
*/
private void erzeugeSchemaTypUndElementFuerProfElement(Node xmlNodeElement,
XSSchemaSet ssQuellSchema, List xsElementsToInsert,
List xsElementsInserted, MySchemaWriter schemaWriter)
throws XPathExpressionException {
// Name des XML-Knotens in der Profilkonfiguration
String strXmlElementName = XsdXmlHelper
.xpathSuche("./name/text()", xmlNodeElement).item(0)
.getNodeValue();
// Passendes SchemaElement erzeugen
SchemaElement currSchemaElement = configurator
.getSchemaElement(strXmlElementName);
// passendes Element im Schema suchen
XSElementDecl currXsElement = ssQuellSchema.getElementDecl(
currSchemaElement.getNsUrl(), currSchemaElement.getName());
if (currXsElement != null) {
erzeugeSchemaTypUndElement(currXsElement, xmlNodeElement,
ssQuellSchema, xsElementsToInsert, xsElementsInserted,
schemaWriter);
}
}
/**
* F�r das angegebene Schema-Element wird unter Ber�cksichtigung der
* Profilkonfiguration der entsprechende Eintrag f�r das profilierte Schema
* erzeugt.
*
* @param currXsElement
* Zu bearbeitendes Schema-Element, das in der profilierte Schema
* �bernommen werden soll
* @param xmlNodeElement
* XML-Knoten aus der Konfiguration f�r dieses Element
* @param ssQuellSchema
* Quellschema mit allen Elementen und Typen
* @param xsElementsToInsert
* Liste aller Elemente, die im aktuellen Profil verwendet
* werden; diese werden erst gesammelt und nach den Typen
* geschrieben.
* @param xsElementsInserted
* Liste aller Elemente, die bereits hinzugef�gt wurden
* @param schemaWriter
* Objekt zum Erzeugen des XML-Textes f�r die zu erzeugende
* Schemadatei
*/
private void erzeugeSchemaTypUndElement(XSElementDecl currXsElement,
Node xmlNodeElement, XSSchemaSet ssQuellSchema,
List xsElementsToInsert,
List xsElementsInserted, MySchemaWriter schemaWriter) {
if (!xsElementsInserted.contains(currXsElement)) {
// angegebenen Typ bestimmen
XSType currXsType = currXsElement.getType();
if ((currXsType != null) && (currXsType.getName() == null)) {
// Typ hat keine Bezeichnung und muss mit dem Element sofort
// geschrieben werden
schemaWriter.elementDecl(currXsElement, "", null,
xmlNodeElement, "");
xsElementsInserted.add(currXsElement);
} else {
// XSD-Element im Zielschema einf�gen
xsElementsToInsert.add(currXsElement);
if (currXsType != null) {
// XSD-Typ schreiben
if (currXsType instanceof XSComplexType) {
schemaWriter.complexType(currXsType.asComplexType(),
null, xmlNodeElement);
} else if (currXsType instanceof XSSimpleType) {
schemaWriter.simpleType(currXsType.asSimpleType(),
null, xmlNodeElement);
}
}
}
}
}
/**
* Im SchemaWriter sind alle referenzierten Typen aufgesammelt worden; diese
* werden mit dieser Methode geschrieben. Dabei wird ber�cksichtigt, dass
* hierbei wieder Typen referenziert sein k�nnen.
*
* @param sw
* Objekt zum Erzeugen des XML-Textes f�r die zu erzeugende
* Schemadatei
* @param ssQuellSchema
* Quellschema mit allen Elementen und Typen
* @param xsElementsToInsert
* Liste aller Elemente, die im aktuellen Profil verwendet
* werden; diese werden erst gesammelt und nach den Typen
* geschrieben.
* @param xsElementsInserted
* Liste aller Elemente, die bereits geschrieben wurden
*/
private void printRefElements(MySchemaWriter sw, XSSchemaSet ssQuellSchema,
List xsElementsToInsert,
List xsElementsInserted) {
// Liste kopieren
List listElementsRef = new LinkedList();
for (XSElementDecl currElement : sw.getXsElementsReferenced()) {
listElementsRef.add(currElement);
}
// interne Liste SchemaWriter zur�cksetzen
sw.setXsElementsReferenced(new LinkedList());
// Elemente behandeln
for (XSElementDecl currElement : listElementsRef) {
if (!xsElementsInserted.contains(currElement)
&& !xsElementsToInsert.contains(currElement)) {
erzeugeSchemaTypUndElement(currElement, null, ssQuellSchema,
xsElementsToInsert, xsElementsInserted, sw);
}
}
// Falls wieder neue Elemente vorhanden sind, rekursiver Aufruf
if (sw.getXsElementsReferenced().size() > 0) {
printRefElements(sw, ssQuellSchema, xsElementsToInsert,
xsElementsInserted);
}
}
/**
* Mit dieser Methode wird ein leeres DOM-Dokument mit dem Wurzelelement
* erzeugt.
*
* @param strRootElement
* Bezeichnung des Wurzelelements
* @return Leeres DOM-Dokument mit Wurzelelement
* @throws ParserConfigurationException
*/
private Document erzeugeLeeresDokument(String strRootElement)
throws ParserConfigurationException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
docFactory.setNamespaceAware(true);
DocumentBuilder parser = docFactory.newDocumentBuilder();
// Leeres DOM Dokument erstellen
Document doc = parser.newDocument();
// root-Element erstellen
Element root = doc.createElement(strRootElement);
// root-Element dem Dokument hinzuf�gen
doc.appendChild(root);
return doc;
}
}