Squash commit of ws-transfer implementation from Erich Duda (dudaerich) This closes #33
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/517ef67f Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/517ef67f Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/517ef67f Branch: refs/heads/master-jaxrs-2.1 Commit: 517ef67f1a69d386de44153e5e09d51cb47bf4d7 Parents: e158c96 Author: Daniel Kulp <dk...@apache.org> Authored: Tue May 24 09:26:41 2016 -0400 Committer: Daniel Kulp <dk...@apache.org> Committed: Tue May 24 09:26:41 2016 -0400 ---------------------------------------------------------------------- rt/ws/pom.xml | 1 + rt/ws/transfer/pom.xml | 91 +++ .../apache/cxf/ws/transfer/dialect/Dialect.java | 64 ++ .../dialect/fragment/FragmentDialect.java | 622 +++++++++++++++++++ .../fragment/FragmentDialectConstants.java | 51 ++ .../dialect/fragment/faults/FragmentFault.java | 44 ++ .../fragment/faults/InvalidExpression.java | 42 ++ .../fragment/faults/UnsupportedLanguage.java | 41 ++ .../fragment/faults/UnsupportedMode.java | 42 ++ .../language/FragmentDialectLanguage.java | 37 ++ .../language/FragmentDialectLanguageQName.java | 134 ++++ .../FragmentDialectLanguageXPath10.java | 160 +++++ .../transfer/manager/MemoryResourceManager.java | 160 +++++ .../ws/transfer/manager/ResourceManager.java | 59 ++ .../cxf/ws/transfer/resource/Resource.java | 101 +++ .../cxf/ws/transfer/resource/ResourceLocal.java | 191 ++++++ .../ws/transfer/resource/ResourceRemote.java | 49 ++ .../resourcefactory/ResourceFactory.java | 61 ++ .../resourcefactory/ResourceFactoryImpl.java | 153 +++++ .../resolver/ResourceReference.java | 61 ++ .../resolver/ResourceResolver.java | 39 ++ .../resolver/SimpleResourceResolver.java | 69 ++ .../ws/transfer/shared/TransferConstants.java | 60 ++ .../shared/faults/InvalidRepresentation.java | 41 ++ .../ws/transfer/shared/faults/PutDenied.java | 44 ++ .../transfer/shared/faults/UnknownDialect.java | 43 ++ .../transfer/shared/faults/UnknownResource.java | 42 ++ .../transfer/shared/faults/WSTransferFault.java | 45 ++ .../ResourceTransformer.java | 30 + .../ResourceTypeIdentifier.java | 36 ++ .../ResourceTypeIdentifierResult.java | 56 ++ .../ResourceValidator.java | 31 + .../ValidAndTransformHelper.java | 63 ++ .../XSDResourceTypeIdentifier.java | 87 +++ .../XSDResourceValidator.java | 88 +++ .../XSLTResourceTransformer.java | 87 +++ .../reference-parameter-parsing.xml | 27 + .../main/resources/schemas/catalog-fragment.cat | 21 + .../src/main/resources/schemas/catalog.cat | 23 + .../src/main/resources/schemas/fragment.xsd | 87 +++ .../src/main/resources/schemas/transfer.xjb | 37 ++ .../src/main/resources/schemas/transfer.xsd | 192 ++++++ .../src/main/resources/schemas/ws-addr.xsd | 141 +++++ .../integration/FragmentGetQNameTest.java | 171 +++++ .../integration/FragmentGetXPath10Test.java | 333 ++++++++++ .../integration/FragmentPutAddTest.java | 238 +++++++ .../integration/FragmentPutInsertAfterTest.java | 194 ++++++ .../FragmentPutInsertBeforeTest.java | 194 ++++++ .../integration/FragmentPutRemoveTest.java | 113 ++++ .../integration/FragmentPutReplaceTest.java | 419 +++++++++++++ .../integration/IntegrationBaseTest.java | 196 ++++++ .../integration/ResourceFactoryTest.java | 135 ++++ .../ws/transfer/integration/ResourceTest.java | 168 +++++ .../unit/MemoryResourceManagerTest.java | 204 ++++++ .../transfer/unit/XSDResourceValidatorTest.java | 60 ++ .../unit/XSLTResourceTransformerTest.java | 60 ++ .../invalidRepresentation.xml | 26 + .../xml/xsdresourcevalidator/schema.xsd | 35 ++ .../validRepresentation.xml | 27 + .../xsltresourcetransformer/representation.xml | 26 + .../xml/xsltresourcetransformer/stylesheet.xsl | 43 ++ systests/pom.xml | 3 +- systests/ws-transfer/pom.xml | 61 ++ .../systest/ws/transfer/CreateStudentTest.java | 103 +++ .../systest/ws/transfer/CreateTeacherTest.java | 91 +++ .../cxf/systest/ws/transfer/DeleteTest.java | 118 ++++ .../apache/cxf/systest/ws/transfer/GetTest.java | 111 ++++ .../apache/cxf/systest/ws/transfer/PutTest.java | 129 ++++ .../cxf/systest/ws/transfer/TestUtils.java | 174 ++++++ .../cxf/systest/ws/transfer/UIDManager.java | 40 ++ .../transfer/resolver/MyResourceResolver.java | 55 ++ .../validator/StudentPutResourceValidator.java | 47 ++ .../validator/TeacherResourceValidator.java | 51 ++ .../src/test/resources/schema/studentCreate.xsd | 46 ++ .../src/test/resources/schema/studentPut.xsd | 47 ++ .../src/test/resources/schema/teacher.xsd | 47 ++ .../resources/schema/teacherCreateBasic.xsd | 35 ++ .../src/test/resources/xml/createStudent.xml | 31 + .../test/resources/xml/createStudentPartial.xml | 29 + .../test/resources/xml/createStudentWrong.xml | 32 + .../src/test/resources/xml/createTeacher.xml | 31 + .../test/resources/xml/createTeacherPartial.xml | 25 + .../test/resources/xml/createTeacherWrong.xml | 32 + .../src/test/resources/xml/putStudent.xml | 32 + .../src/test/resources/xml/putTeacher.xml | 32 + .../src/test/resources/xml/random.xml | 24 + .../src/test/resources/xslt/studentCreate.xsl | 110 ++++ .../src/test/resources/xslt/studentPut.xsl | 108 ++++ .../test/resources/xslt/teacherCreateBasic.xsl | 45 ++ .../resources/xslt/teacherDefaultValues.xsl | 108 ++++ 90 files changed, 7991 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/pom.xml ---------------------------------------------------------------------- diff --git a/rt/ws/pom.xml b/rt/ws/pom.xml index 0bea25c..70e1c97 100644 --- a/rt/ws/pom.xml +++ b/rt/ws/pom.xml @@ -36,5 +36,6 @@ <module>rm</module> <module>mex</module> <module>eventing</module> + <module>transfer</module> </modules> </project> http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/pom.xml ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/pom.xml b/rt/ws/transfer/pom.xml new file mode 100644 index 0000000..d2c1a09 --- /dev/null +++ b/rt/ws/transfer/pom.xml @@ -0,0 +1,91 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <artifactId>cxf-rt-ws-transfer</artifactId> + <packaging>jar</packaging> + <name>Apache CXF Runtime WS Transfer</name> + <url>http://cxf.apache.org</url> + + <parent> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-parent</artifactId> + <version>3.2.0-SNAPSHOT</version> + <relativePath>../../../parent/pom.xml</relativePath> + </parent> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>cxf-rt-frontend-jaxws</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>cxf-rt-transports-local</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-xjc-plugin</artifactId> + <version>${cxf.xjc-utils.version}</version> + <executions> + <execution> + <id>generate-transfer</id> + <phase>generate-sources</phase> + <goals> + <goal>xsdtojava</goal> + </goals> + <configuration> + <sourceRoot>${basedir}/target/generated-sources/xjc</sourceRoot> + <xsdOptions> + <xsdOption> + <xsd>${basedir}/src/main/resources/schemas/transfer.xsd</xsd> + <packagename>org.apache.cxf.ws.transfer</packagename> + <bindingFile>${basedir}/src/main/resources/schemas/transfer.xjb</bindingFile> + <catalog>${basedir}/src/main/resources/schemas/catalog.cat</catalog> + </xsdOption> + </xsdOptions> + </configuration> + </execution> + <execution> + <id>generate-fragment</id> + <phase>generate-sources</phase> + <goals> + <goal>xsdtojava</goal> + </goals> + <configuration> + <sourceRoot>${basedir}/target/generated-sources/xjc</sourceRoot> + <xsdOptions> + <xsdOption> + <xsd>${basedir}/src/main/resources/schemas/fragment.xsd</xsd> + <packagename>org.apache.cxf.ws.transfer.dialect.fragment</packagename> + <catalog>${basedir}/src/main/resources/schemas/catalog-fragment.cat</catalog> + </xsdOption> + </xsdOptions> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/Dialect.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/Dialect.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/Dialect.java new file mode 100644 index 0000000..6ea5208 --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/Dialect.java @@ -0,0 +1,64 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect; + +import org.apache.cxf.ws.transfer.Create; +import org.apache.cxf.ws.transfer.Delete; +import org.apache.cxf.ws.transfer.Get; +import org.apache.cxf.ws.transfer.Put; +import org.apache.cxf.ws.transfer.Representation; + +/** + * The interface for a Dialect objects. + */ +public interface Dialect { + + /** + * Method for processing incoming Get message by Dialect extension. + * @param body Get body + * @param representation XML representation stored in the ResourceManager + * @return Representation, which will be returned in response. + */ + Object processGet(Get body, Representation representation); + + /** + * Method for processing incoming Put message by Dialect extension. + * @param body Put body + * @param representation XML representation stored in the ResourceManager + * @return Representation, which will be stored in ResourceManager. + */ + Representation processPut(Put body, Representation representation); + + /** + * Method for processing incoming Delete message by Dialect extension. + * @param body Delete body + * @param representation XML representation stored in the ResourceManager + * @return Representation, which will be stored in ResourceManager. + */ + boolean processDelete(Delete body, Representation representation); + + /** + * Method for processing incoming Create message by Dialect extension. + * @param body Create body + * @return Representation, which will be stored in ResourceManager. + */ + Representation processCreate(Create body); + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/FragmentDialect.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/FragmentDialect.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/FragmentDialect.java new file mode 100644 index 0000000..8498ff8 --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/FragmentDialect.java @@ -0,0 +1,622 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.annotation.Resource; +import javax.xml.bind.JAXBElement; +import javax.xml.ws.WebServiceContext; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.apache.cxf.binding.soap.SoapFault; +import org.apache.cxf.binding.soap.SoapMessage; +import org.apache.cxf.binding.soap.SoapVersion; +import org.apache.cxf.helpers.DOMUtils; +import org.apache.cxf.jaxws.context.WrappedMessageContext; +import org.apache.cxf.ws.transfer.Create; +import org.apache.cxf.ws.transfer.Delete; +import org.apache.cxf.ws.transfer.Get; +import org.apache.cxf.ws.transfer.Put; +import org.apache.cxf.ws.transfer.Representation; +import org.apache.cxf.ws.transfer.dialect.Dialect; +import org.apache.cxf.ws.transfer.dialect.fragment.faults.InvalidExpression; +import org.apache.cxf.ws.transfer.dialect.fragment.faults.UnsupportedLanguage; +import org.apache.cxf.ws.transfer.dialect.fragment.faults.UnsupportedMode; +import org.apache.cxf.ws.transfer.dialect.fragment.language.FragmentDialectLanguage; +import org.apache.cxf.ws.transfer.dialect.fragment.language.FragmentDialectLanguageQName; +import org.apache.cxf.ws.transfer.dialect.fragment.language.FragmentDialectLanguageXPath10; +import org.apache.cxf.ws.transfer.shared.faults.InvalidRepresentation; +import org.apache.cxf.ws.transfer.shared.faults.UnknownDialect; + +/** + * Implementation of the WS-Fragment dialect. + */ +public class FragmentDialect implements Dialect { + + @Resource + WebServiceContext context; + + private final Map<String, FragmentDialectLanguage> languages; + + private Pattern badXPathPattern; + + private Pattern goodXPathPattern; + + public FragmentDialect() { + languages = new HashMap<String, FragmentDialectLanguage>(); + languages.put(FragmentDialectConstants.QNAME_LANGUAGE_IRI, new FragmentDialectLanguageQName()); + languages.put(FragmentDialectConstants.XPATH10_LANGUAGE_IRI, new FragmentDialectLanguageXPath10()); + if (badXPathPattern == null) { + StringBuilder sb = new StringBuilder(); + sb.append("//@?"); + sb.append(FragmentDialectLanguageQName.getQNamePatternString()); + sb.append("$"); + badXPathPattern = Pattern.compile(sb.toString()); + } + if (goodXPathPattern == null) { + StringBuilder sb = new StringBuilder(); + sb.append("/@?"); + sb.append(FragmentDialectLanguageQName.getQNamePatternString()); + sb.append("$"); + goodXPathPattern = Pattern.compile(sb.toString()); + } + } + + @Override + public JAXBElement<ValueType> processGet(Get body, Representation representation) { + for (Object o : body.getAny()) { + if (o instanceof JAXBElement<?> && ((JAXBElement<?>)o).getDeclaredType() == ExpressionType.class) { + ExpressionType expression = (ExpressionType) ((JAXBElement<?>)o).getValue(); + String languageIRI = expression.getLanguage(); + languageIRI = languageIRI == null ? FragmentDialectConstants.XPATH10_LANGUAGE_IRI : languageIRI; + if (languages.containsKey(languageIRI)) { + FragmentDialectLanguage language = languages.get(languageIRI); + return generateGetResponse(language.getResourceFragment(representation, expression)); + } else { + throw new UnsupportedLanguage(); + } + } + } + throw new SoapFault("wsf:Expression is not present.", getSoapVersion().getSender()); + } + + @Override + public Representation processPut(Put body, Representation representation) { + for (Object o : body.getAny()) { + if (o instanceof Fragment) { + Fragment fragment = (Fragment) o; + ExpressionType expression = fragment.getExpression(); + ValueType value = fragment.getValue(); + + if (expression == null) { + throw new SoapFault("wsf:Expression is not present.", getSoapVersion().getSender()); + } + if (value == null) { + value = new ValueType(); + } + String languageIRI = expression.getLanguage(); + languageIRI = languageIRI == null ? FragmentDialectConstants.XPATH10_LANGUAGE_IRI : languageIRI; + if (languages.containsKey(languageIRI)) { + FragmentDialectLanguage language = languages.get(languageIRI); + Object resourceFragment = language.getResourceFragment(representation, expression); + String mode = expression.getMode(); + mode = mode == null ? FragmentDialectConstants.FRAGMENT_MODE_REPLACE : mode; + if (resourceFragment == null && FragmentDialectConstants.FRAGMENT_MODE_REPLACE.equals(mode) + && FragmentDialectConstants.XPATH10_LANGUAGE_IRI.equals(languageIRI)) { + resourceFragment = language.getResourceFragment(representation, getParentXPath(expression)); + mode = FragmentDialectConstants.FRAGMENT_MODE_ADD; + } + return modifyRepresentation(resourceFragment, mode, value); + } else { + throw new UnsupportedLanguage(); + } + } + } + throw new SoapFault("wsf:Fragment is not present.", getSoapVersion().getSender()); + } + + @Override + public boolean processDelete(Delete body, Representation representation) { + throw new UnknownDialect(); + } + + @Override + public Representation processCreate(Create body) { + throw new UnknownDialect(); + } + + /** + * Register FragmentDialectLanguage object for IRI. + * @param iri + * @param language + */ + public void registerLanguage(String iri, FragmentDialectLanguage language) { + if (languages.containsKey(iri)) { + throw new IllegalArgumentException(String.format("IRI \"%s\" is already registered", iri)); + } + languages.put(iri, language); + } + + /** + * Unregister FragmentDialectLanguage object for IRI. + * @param iri + */ + public void unregisterLanguage(String iri) { + if (!languages.containsKey(iri)) { + throw new IllegalArgumentException(String.format("IRI \"%s\" is not registered", iri)); + } + languages.remove(iri); + } + + /** + * Generates Value element, which is returned as response to Get request. + * @param value Result of the XPath evaluation. + * @return + */ + private JAXBElement<ValueType> generateGetResponse(Object value) { + if (value instanceof Node) { + return generateGetResponseNode((Node) value); + } else if (value instanceof NodeList) { + return generateGetResponseNodeList((NodeList) value); + } else if (value instanceof String) { + return generateGetResponseString((String) value); + } + ObjectFactory objectFactory = new ObjectFactory(); + return objectFactory.createValue(new ValueType()); + } + + /** + * Generates Value element from NodeList. + * @param nodeList + * @return + */ + private JAXBElement<ValueType> generateGetResponseNodeList(NodeList nodeList) { + ValueType resultValue = new ValueType(); + for (int i = 0; i < nodeList.getLength(); i++) { + resultValue.getContent().add(nodeList.item(i)); + } + ObjectFactory objectFactory = new ObjectFactory(); + return objectFactory.createValue(resultValue); + } + + /** + * Generates Value element from Node. + * @param node + * @return + */ + private JAXBElement<ValueType> generateGetResponseNode(Node node) { + Document doc = DOMUtils.createDocument(); + ValueType resultValue = new ValueType(); + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + Element attrNodeEl = doc.createElementNS( + FragmentDialectConstants.FRAGMENT_2011_03_IRI, + FragmentDialectConstants.FRAGMENT_ATTR_NODE_NAME); + attrNodeEl.setAttribute( + FragmentDialectConstants.FRAGMENT_ATTR_NODE_NAME_ATTR, + node.getNodeName() + ); + attrNodeEl.setTextContent(node.getNodeValue()); + resultValue.getContent().add(attrNodeEl); + } else if (node.getNodeType() == Node.TEXT_NODE) { + Element textNodeEl = doc.createElementNS( + FragmentDialectConstants.FRAGMENT_2011_03_IRI, + FragmentDialectConstants.FRAGMENT_TEXT_NODE_NAME); + textNodeEl.setNodeValue(node.getNodeValue()); + resultValue.getContent().add(textNodeEl); + } else if (node.getNodeType() == Node.ELEMENT_NODE) { + resultValue.getContent().add(node); + } + ObjectFactory objectFactory = new ObjectFactory(); + return objectFactory.createValue(resultValue); + } + + /** + * Generates Value element from String. + * @param value + * @return + */ + private JAXBElement<ValueType> generateGetResponseString(String value) { + ValueType resultValue = new ValueType(); + resultValue.getContent().add(value); + ObjectFactory objectFactory = new ObjectFactory(); + return objectFactory.createValue(resultValue); + } + + /** + * Returns expression containing XPath, which refers to parent element. + * @param expression + * @return + */ + private ExpressionType getParentXPath(ExpressionType expression) { + String expr; + if (expression.getContent().size() == 1) { + expr = (String) expression.getContent().get(0); + } else { + throw new InvalidExpression(); + } + if (badXPathPattern.matcher(expr).find()) { + throw new InvalidExpression(); + } + if (goodXPathPattern.matcher(expr).find()) { + expression.getContent().clear(); + expr = expr.replaceFirst(goodXPathPattern.pattern(), ""); + if (expr.isEmpty()) { + expr = "/"; + } + expression.getContent().add(expr); + return expression; + } else { + throw new InvalidExpression(); + } + } + + /** + * Process Put requests. + * @param resourceFragment Result of the XPath evaluation. It can be Node or NodeList. + * @param mode Mode defined in the Mode attribute. + * @param value Value defined in the Value element. + * @return Representation element, which is returned as response. + */ + private Representation modifyRepresentation( + Object resourceFragment, + String mode, + ValueType value) { + if (resourceFragment instanceof Node) { + List<Node> nodeList = new ArrayList<Node>(); + nodeList.add((Node) resourceFragment); + return modifyRepresentationMode(nodeList, mode, value); + } else if (resourceFragment instanceof NodeList) { + NodeList rfNodeList = (NodeList) resourceFragment; + List<Node> nodeList = new ArrayList<Node>(); + for (int i = 0; i < rfNodeList.getLength(); i++) { + nodeList.add(rfNodeList.item(i)); + } + return modifyRepresentationMode(nodeList, mode, value); + } else { + throw new InvalidExpression(); + } + } + + /** + * Process Put requests. + * @param mode Mode defined in the Mode attribute. + * @param value Value defined in the Value element. + * @return Representation element, which is returned as response. + */ + private Representation modifyRepresentationMode( + List<Node> nodeList, + String mode, + ValueType value) { + switch (mode) { + case FragmentDialectConstants.FRAGMENT_MODE_REPLACE: + return modifyRepresentationModeReplace(nodeList, value); + case FragmentDialectConstants.FRAGMENT_MODE_ADD: + return modifyRepresentationModeAdd(nodeList, value); + case FragmentDialectConstants.FRAGMENT_MODE_INSERT_BEFORE: + return modifyRepresentationModeInsertBefore(nodeList, value); + case FragmentDialectConstants.FRAGMENT_MODE_INSERT_AFTER: + return modifyRepresentationModeInsertAfter(nodeList, value); + case FragmentDialectConstants.FRAGMENT_MODE_REMOVE: + return modifyRepresentationModeRemove(nodeList, value); + default: + throw new UnsupportedMode(); + } + } + + /** + * Process Put requests for Replace mode. + * @param value Value defined in the Value element. + * @return Representation element, which is returned as response. + */ + private Representation modifyRepresentationModeReplace( + List<Node> nodeList, + ValueType value) { + + if (nodeList.isEmpty()) { + throw new InvalidExpression(); + } + Node firstNode = nodeList.get(0); + Document ownerDocument = firstNode.getOwnerDocument(); + // if firstNode.getOwnerDocument == null the firstNode is ownerDocument + ownerDocument = ownerDocument == null ? (Document) firstNode : ownerDocument; + Node nextSibling = null; + Node parent = null; + + for (Node node : nodeList) { + nextSibling = node.getNextSibling(); + parent = removeNode(node); + } + + addNode(ownerDocument, parent, nextSibling, value); + + Representation representation = new Representation(); + representation.setAny(ownerDocument.getDocumentElement()); + return representation; + } + + /** + * Process Put requests for Add mode. + * @param value Value defined in the Value element. + * @return Representation element, which is returned as response. + */ + private Representation modifyRepresentationModeAdd( + List<Node> nodeList, + ValueType value) { + if (nodeList.isEmpty()) { + throw new InvalidExpression(); + } + Node firstNode = nodeList.get(0); + Document ownerDocument = firstNode.getOwnerDocument(); + // if firstNode.getOwnerDocument == null the firstNode is ownerDocument + ownerDocument = ownerDocument == null ? (Document) firstNode : ownerDocument; + + for (Node node : nodeList) { + addNode(ownerDocument, node, null, value); + } + Representation representation = new Representation(); + representation.setAny(ownerDocument.getDocumentElement()); + return representation; + } + + /** + * Process Put requests for InsertBefore mode. + * @param value Value defined in the Value element. + * @return Representation element, which is returned as response. + */ + private Representation modifyRepresentationModeInsertBefore( + List<Node> nodeList, + ValueType value) { + if (nodeList.isEmpty()) { + throw new InvalidExpression(); + } + Node firstNode = nodeList.get(0); + Document ownerDocument = firstNode.getOwnerDocument(); + // if firstNode.getOwnerDocument == null the firstNode is ownerDocument + ownerDocument = ownerDocument == null ? (Document) firstNode : ownerDocument; + + Node parent = firstNode.getParentNode(); + if (parent == null && firstNode.getNodeType() != Node.DOCUMENT_NODE) { + throw new InvalidExpression(); + } + if (parent == null) { + parent = firstNode; + if (((Document) parent).getDocumentElement() != null) { + throw new InvalidExpression(); + } + } + + for (Node node : nodeList) { + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + throw new InvalidRepresentation(); + } + insertBefore(ownerDocument, parent, node, value); + } + + Representation representation = new Representation(); + representation.setAny(ownerDocument.getDocumentElement()); + return representation; + } + + /** + * Process Put requests for InsertAfter mode. + * @param value Value defined in the Value element. + * @return Representation element, which is returned as response. + */ + private Representation modifyRepresentationModeInsertAfter( + List<Node> nodeList, + ValueType value) { + if (nodeList.isEmpty()) { + throw new InvalidExpression(); + } + Node firstNode = nodeList.get(0); + Document ownerDocument = firstNode.getOwnerDocument(); + // if firstNode.getOwnerDocument == null the firstNode is ownerDocument + ownerDocument = ownerDocument == null ? (Document) firstNode : ownerDocument; + + Node parent = firstNode.getParentNode(); + if (parent == null && firstNode.getNodeType() != Node.DOCUMENT_NODE) { + throw new InvalidExpression(); + } + if (parent == null) { + parent = firstNode; + if (((Document) parent).getDocumentElement() != null) { + throw new InvalidExpression(); + } + } + + for (Node node : nodeList) { + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + throw new InvalidRepresentation(); + } + insertAfter(ownerDocument, parent, node, value); + } + + Representation representation = new Representation(); + representation.setAny(ownerDocument.getDocumentElement()); + return representation; + } + + /** + * Process Put requests for Remove mode. + * @param value Value defined in the Value element. + * @return Representation element, which is returned as response. + */ + private Representation modifyRepresentationModeRemove( + List<Node> nodeList, + ValueType value) { + if (nodeList.isEmpty()) { + throw new InvalidExpression(); + } + Node firstNode = nodeList.get(0); + Document ownerDocument = firstNode.getOwnerDocument(); + // if firstNode.getOwnerDocument == null the firstNode is ownerDocument + ownerDocument = ownerDocument == null ? (Document) firstNode : ownerDocument; + + for (Node node : nodeList) { + removeNode(node); + } + + Representation representation = new Representation(); + representation.setAny(ownerDocument.getDocumentElement()); + return representation; + } + + /** + * Helper method. It removes Node and returns its parent. + * @param resourceFragment Node to remove. + * @return Parent of removed Node. + */ + private Node removeNode(Node resourceFragment) { + Node parent = null; + if (resourceFragment.getNodeType() == Node.ATTRIBUTE_NODE) { + parent = ((Attr)resourceFragment).getOwnerElement(); + } else { + parent = resourceFragment.getParentNode(); + } + if (parent == null) { + // resourceFragment is Document Node + parent = resourceFragment; + } + if (resourceFragment.getNodeType() == Node.ATTRIBUTE_NODE) { + ((Element)parent).removeAttributeNode((Attr)resourceFragment); + } else { + if (parent != resourceFragment) { + parent.removeChild(resourceFragment); + } else { + // Both parent and resourceFragment are Document + Document doc = (Document) parent; + if (doc.getDocumentElement() != null) { + doc.removeChild(doc.getDocumentElement()); + } + } + } + + return parent; + } + + private void insertAfter(Document ownerDocument, Node parent, Node refChild, ValueType value) { + for (Object o : value.getContent()) { + if (o instanceof Node) { + Node node = (Node) o; + + if ( + FragmentDialectConstants.FRAGMENT_2011_03_IRI.equals(node.getNamespaceURI()) + && FragmentDialectConstants.FRAGMENT_ATTR_NODE_NAME.equals(node.getLocalName())) { + throw new InvalidRepresentation(); + } + + Node importedNode = ownerDocument.importNode(node, true); + if (parent.getNodeType() == Node.DOCUMENT_NODE) { + parent.appendChild(importedNode); + } else { + Node nextSibling = refChild.getNextSibling(); + if (nextSibling == null) { + parent.appendChild(importedNode); + } else { + parent.insertBefore(importedNode, nextSibling); + } + } + } else { + throw new InvalidExpression(); + } + } + } + + private void insertBefore(Document ownerDocument, Node parent, Node refChild, ValueType value) { + for (Object o : value.getContent()) { + if (o instanceof Node) { + Node node = (Node) o; + + if ( + FragmentDialectConstants.FRAGMENT_2011_03_IRI.equals(node.getNamespaceURI()) + && FragmentDialectConstants.FRAGMENT_ATTR_NODE_NAME.equals(node.getLocalName())) { + throw new InvalidRepresentation(); + } + + Node importedNode = ownerDocument.importNode(node, true); + if (parent.getNodeType() == Node.DOCUMENT_NODE) { + parent.appendChild(importedNode); + } else { + parent.insertBefore(importedNode, refChild); + } + } else { + throw new InvalidExpression(); + } + } + } + + /** + * Helper method. It adds new Node as the last child of parent. + * @param ownerDocument Document, where the Node is added. + * @param parent Parent, where the Node is added. + * @param value Value defined in the Value element. It represents newly added Node. + */ + private void addNode(Document ownerDocument, Node parent, Node nextSibling, ValueType value) { + if (ownerDocument == parent && ownerDocument.getDocumentElement() != null) { + throw new InvalidRepresentation(); + } + for (Object o : value.getContent()) { + if (o instanceof String) { + parent.setTextContent(parent.getTextContent() + ((String) o)); + } else if (o instanceof Node) { + Node node = (Node) o; + if ( + FragmentDialectConstants.FRAGMENT_2011_03_IRI.equals(node.getNamespaceURI()) + && FragmentDialectConstants.FRAGMENT_ATTR_NODE_NAME.equals(node.getLocalName())) { + String attrName = ((Element)node).getAttributeNS( + FragmentDialectConstants.FRAGMENT_2011_03_IRI, + FragmentDialectConstants.FRAGMENT_ATTR_NODE_NAME_ATTR); + String attrValue = node.getTextContent(); + if (attrName == null) { + throw new SoapFault("wsf:AttributeNode@name is not present.", getSoapVersion().getSender()); + } + if (((Element) parent).hasAttribute(attrName)) { + throw new InvalidRepresentation(); + } + ((Element) parent).setAttribute(attrName, attrValue); + } else { + // import the node to the ownerDocument + Node importedNode = ownerDocument.importNode((Node) o, true); + if (nextSibling == null) { + parent.appendChild(importedNode); + } else { + parent.insertBefore(importedNode, nextSibling); + } + } + } else { + throw new InvalidExpression(); + } + } + } + + private SoapVersion getSoapVersion() { + WrappedMessageContext wmc = (WrappedMessageContext) context.getMessageContext(); + SoapMessage message = (SoapMessage) wmc.getWrappedMessage(); + return message.getVersion(); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/FragmentDialectConstants.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/FragmentDialectConstants.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/FragmentDialectConstants.java new file mode 100644 index 0000000..6ffd009 --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/FragmentDialectConstants.java @@ -0,0 +1,51 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment; + +/** + * Helper class for holding of constants. + */ +public final class FragmentDialectConstants { + + public static final String FRAGMENT_2011_03_IRI = "http://www.w3.org/2011/03/ws-fra"; + + public static final String QNAME_LANGUAGE_IRI = "http://www.w3.org/2011/03/ws-fra/QName"; + + public static final String XPATH10_LANGUAGE_IRI = "http://www.w3.org/2011/03/ws-fra/XPath10"; + + public static final String FRAGMENT_TEXT_NODE_NAME = "TextNode"; + + public static final String FRAGMENT_ATTR_NODE_NAME = "AttributeNode"; + + public static final String FRAGMENT_ATTR_NODE_NAME_ATTR = "name"; + + public static final String FRAGMENT_MODE_REPLACE = "http://www.w3.org/2011/03/ws-fra/Modes/Replace"; + + public static final String FRAGMENT_MODE_ADD = "http://www.w3.org/2011/03/ws-fra/Modes/Add"; + + public static final String FRAGMENT_MODE_INSERT_BEFORE = "http://www.w3.org/2011/03/ws-fra/Modes/InsertBefore"; + + public static final String FRAGMENT_MODE_INSERT_AFTER = "http://www.w3.org/2011/03/ws-fra/Modes/InsertAfter"; + + public static final String FRAGMENT_MODE_REMOVE = "http://www.w3.org/2011/03/ws-fra/Modes/Remove"; + + private FragmentDialectConstants() { + + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/FragmentFault.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/FragmentFault.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/FragmentFault.java new file mode 100644 index 0000000..3777238 --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/FragmentFault.java @@ -0,0 +1,44 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment.faults; + +import javax.xml.namespace.QName; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.apache.cxf.binding.soap.SoapFault; +import org.apache.cxf.helpers.DOMUtils; + +/** + * The parent for all WS-Fragment-specific faults. + */ +public abstract class FragmentFault extends SoapFault { + + private static final long serialVersionUID = 2111286624025926462L; + + public FragmentFault(String reason, String detail, QName faultCode) { + super(reason, faultCode); + if (detail != null) { + Document doc = DOMUtils.createDocument(); + Element detailEl = doc.createElement("detail"); + detailEl.setTextContent(detail); + setDetail(detailEl); + } + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/InvalidExpression.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/InvalidExpression.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/InvalidExpression.java new file mode 100644 index 0000000..23da1bc --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/InvalidExpression.java @@ -0,0 +1,42 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment.faults; + +import javax.xml.namespace.QName; +import org.apache.cxf.ws.transfer.dialect.fragment.FragmentDialectConstants; + +/** + * Definition of the InvalidExpression SOAPFault. + */ +public class InvalidExpression extends FragmentFault { + + private static final long serialVersionUID = -1920756304737648952L; + + private static final String SUBCODE = "InvalidExpression"; + + private static final String REASON = "The specified Language expression is invalid."; + + private static final String DETAIL = "The invalid language expression."; + + public InvalidExpression() { + super(REASON, DETAIL, + new QName(FragmentDialectConstants.FRAGMENT_2011_03_IRI, SUBCODE)); + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/UnsupportedLanguage.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/UnsupportedLanguage.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/UnsupportedLanguage.java new file mode 100644 index 0000000..bb13b4c --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/UnsupportedLanguage.java @@ -0,0 +1,41 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment.faults; + +import javax.xml.namespace.QName; +import org.apache.cxf.ws.transfer.dialect.fragment.FragmentDialectConstants; + +/** + * Definition of the UnsupportedLanguage SOAPFault. + */ +public class UnsupportedLanguage extends FragmentFault { + + private static final long serialVersionUID = 7627652802987243575L; + + private static final String SUBCODE = "UnsupportedLanguage"; + + private static final String REASON = "The specified Language IRI is not supported."; + + private static final String DETAIL = "The unsupported Language IRI."; + + public UnsupportedLanguage() { + super(REASON, DETAIL, + new QName(FragmentDialectConstants.FRAGMENT_2011_03_IRI, SUBCODE)); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/UnsupportedMode.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/UnsupportedMode.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/UnsupportedMode.java new file mode 100644 index 0000000..f38b912 --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/faults/UnsupportedMode.java @@ -0,0 +1,42 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment.faults; + +import javax.xml.namespace.QName; +import org.apache.cxf.ws.transfer.dialect.fragment.FragmentDialectConstants; + +/** + * Definition of the UnsupportedMode SOAPFault. + */ +public class UnsupportedMode extends FragmentFault { + + private static final long serialVersionUID = -5824904523582078377L; + + private static final String SUBCODE = "UnsupportedMode"; + + private static final String REASON = "The specified mode is not supported."; + + private static final String DETAIL = "The unsupported Mode."; + + public UnsupportedMode() { + super(REASON, DETAIL, + new QName(FragmentDialectConstants.FRAGMENT_2011_03_IRI, SUBCODE)); + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguage.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguage.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguage.java new file mode 100644 index 0000000..8ff8018 --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguage.java @@ -0,0 +1,37 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment.language; + +import org.apache.cxf.ws.transfer.Representation; +import org.apache.cxf.ws.transfer.dialect.fragment.ExpressionType; + +/** + * Interface for FragmentDialect languages. + */ +public interface FragmentDialectLanguage { + + /** + * Returns fragment of resource, which is described by expression. + * @param representation Resource, from which is fragment computed. + * @param expression Expression written in the language. + * @return It can return org.w3c.dom.Node | org.w3c.dom.NodeList | String + */ + Object getResourceFragment(Representation representation, ExpressionType expression); + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguageQName.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguageQName.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguageQName.java new file mode 100644 index 0000000..a5d78ad --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguageQName.java @@ -0,0 +1,134 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment.language; + +import java.util.Iterator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.xml.namespace.NamespaceContext; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.apache.cxf.helpers.XPathUtils; +import org.apache.cxf.ws.transfer.Representation; +import org.apache.cxf.ws.transfer.dialect.fragment.ExpressionType; +import org.apache.cxf.ws.transfer.dialect.fragment.faults.InvalidExpression; + +/** + * Implementation of the QName language. + */ +public class FragmentDialectLanguageQName implements FragmentDialectLanguage { + + private static Pattern qNamePattern; + + public FragmentDialectLanguageQName() { + if (qNamePattern == null) { + String qName = getQNamePatternString(); + qNamePattern = Pattern.compile("^" + qName); + } + } + + /** + * Returns regex string, which describes QName format. + * @return + */ + public static String getQNamePatternString() { + // See http://www.w3.org/TR/REC-xml-names/#NT-PrefixedName + // NCNameStartChar + // see http://www.w3.org/TR/REC-xml-names/#NT-NCName + // and http://www.w3.org/TR/REC-xml/#NT-NameStartChar + String ncNameStartChar = "[A-Z]|_|[a-z]|[\\x{c0}-\\x{d6}]|[\\x{d8}-\\x{f6}]|[\\x{f8}-\\x{2ff}]|" + + "[\\x{370}-\\x{37d}]|[\\x{37f}-\\x{1fff}]|[\\x{200c}-\\x{200d}]|" + + "[\\x{2070}-\\x{218f}]|[\\x{2c00}-\\x{2fef}]|[\\x{3001}-\\x{d7ff}]|" + + "[\\x{f900}-\\x{fdcf}]|[\\x{fdf0}-\\x{fffd}]|[\\x{10000}-\\x{effff}]"; + // NCNameChar + // see http://www.w3.org/TR/REC-xml/#NT-NameChar + String ncNameChar = ncNameStartChar + + "|-|\\.|[0-9]|\\x{b7}|[\\x{0300}-\\x{036f}]|[\\x{203f}-\\x{2040}]"; + // NCName + // see http://www.w3.org/TR/REC-xml/#NT-Name + String ncName = String.format("(%s)(%s)*", ncNameStartChar, ncNameChar); + // QName + // see http://www.w3.org/TR/REC-xml-names/#NT-QName + return String.format("((%s):)?(%s)", ncName, ncName); + } + + @Override + public Object getResourceFragment(final Representation representation, ExpressionType expression) { + String expressionStr = getXPathFromQNameExpression(expression); + // Evaluate XPath + XPathUtils xu = new XPathUtils(new NamespaceContext() { + @Override + public String getNamespaceURI(String prefix) { + if (prefix != null && !prefix.isEmpty()) { + Element resource = (Element) representation.getAny(); + return resource.getAttribute("xmlns:" + prefix); + } else { + return null; + } + } + + @Override + public String getPrefix(String s) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator<String> getPrefixes(String s) { + throw new UnsupportedOperationException(); + } + }); + Node resource = (Node) representation.getAny(); + if (resource == null) { + // Returns empty NodeList + return new NodeList() { + @Override + public Node item(int i) { + return null; + } + + @Override + public int getLength() { + return 0; + } + }; + } + return xu.getValueList(expressionStr, resource); + } + + /** + * Converts expression in QName language to XPath expression. + * @param expression Expression in QName language. + * @return Expression in XPath language. + */ + private String getXPathFromQNameExpression(ExpressionType expression) { + if (expression.getContent().size() == 1) { + String expressionValue = (String) expression.getContent().get(0); + Matcher m = qNamePattern.matcher(expressionValue); + if (m.matches()) { + return "/node()/" + expressionValue; + } else { + throw new InvalidExpression(); + } + } else { + throw new InvalidExpression(); + } + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguageXPath10.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguageXPath10.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguageXPath10.java new file mode 100644 index 0000000..86bddab --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/dialect/fragment/language/FragmentDialectLanguageXPath10.java @@ -0,0 +1,160 @@ +/** + * 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 org.apache.cxf.ws.transfer.dialect.fragment.language; + +import java.util.Iterator; +import javax.xml.namespace.NamespaceContext; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathException; +import javax.xml.xpath.XPathFactory; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.apache.cxf.helpers.DOMUtils; +import org.apache.cxf.ws.transfer.Representation; +import org.apache.cxf.ws.transfer.dialect.fragment.ExpressionType; +import org.apache.cxf.ws.transfer.dialect.fragment.faults.InvalidExpression; + +/** + * Implementation of the XPath 1.0 language. + */ +public class FragmentDialectLanguageXPath10 implements FragmentDialectLanguage { + + private static XPathFactory xpathFactory = XPathFactory.newInstance(); + + @Override + public Object getResourceFragment(final Representation representation, ExpressionType expression) { + String expressionStr = getXPathFromExpression(expression); + // Evaluate XPath + XPath xPath = xpathFactory.newXPath(); + xPath.setNamespaceContext(new NamespaceContext() { + + @Override + public String getNamespaceURI(String prefix) { + if (prefix != null && !prefix.isEmpty()) { + Element resource = (Element) representation.getAny(); + return resource.getAttribute("xmlns:" + prefix); + } else { + return null; + } + } + + @Override + public String getPrefix(String string) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator<String> getPrefixes(String string) { + throw new UnsupportedOperationException(); + } + }); + try { + Object resource = representation.getAny(); + if (resource == null) { + resource = DOMUtils.createDocument(); + } + NodeList result = (NodeList) xPath.evaluate( + expressionStr, resource, XPathConstants.NODESET); + if (checkResultConstraints(result)) { + if (result.getLength() == 0) { + return null; + } else { + return result; + } + } else { + return result.item(0); + } + } catch (XPathException ex) { + // See https://www.java.net/node/681793 + } + + try { + return (String) xPath.evaluate( + expressionStr, representation.getAny(), XPathConstants.STRING); + } catch (XPathException ex) { + throw new InvalidExpression(); + } + } + + /** + * Get XPath from the Expression element. + * @param expression + * @return + */ + private String getXPathFromExpression(ExpressionType expression) { + if (expression.getContent().size() == 1) { + return (String) expression.getContent().get(0); + } else { + throw new InvalidExpression(); + } + } + + /** + * Check if result from evaluation of XPath expression fullfils constraints + * defined in the specification. + * See http://www.w3.org/TR/ws-fragment/#IdResSubset + * @param result + * @return If the result is true, the server should return all sequence of elements, + * otherwise it should return only the first element. + */ + private boolean checkResultConstraints(NodeList result) { + if (result.getLength() > 0) { + Node firstNode = result.item(0); + if (firstNode.getNodeType() == Node.ELEMENT_NODE) { + Element firstEl = (Element) firstNode; + // QName attributes + String localName = firstEl.getLocalName(); + String namespace = firstEl.getNamespaceURI(); + Node parent = firstEl.getParentNode(); + for (int i = 1; i < result.getLength(); i++) { + Node node = result.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) node; + if (!stringEquals(element.getLocalName(), localName)) { + return false; + } + if (!stringEquals(element.getNamespaceURI(), namespace)) { + return false; + } + if (element.getParentNode() != parent) { + return false; + } + } else { + return false; + } + } + } else { + return false; + } + } + return true; + } + + /** + * Helper method for equation two strings, which can be nullable. + * @param str1 + * @param str2 + * @return + */ + private boolean stringEquals(String str1, String str2) { + return str1 == null ? str2 == null : str1.equals(str2); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/manager/MemoryResourceManager.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/manager/MemoryResourceManager.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/manager/MemoryResourceManager.java new file mode 100644 index 0000000..9609013e --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/manager/MemoryResourceManager.java @@ -0,0 +1,160 @@ +/** + * 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 org.apache.cxf.ws.transfer.manager; + +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Logger; + +import javax.annotation.Resource; +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.ws.WebServiceContext; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.apache.cxf.binding.soap.SoapFault; +import org.apache.cxf.binding.soap.SoapMessage; +import org.apache.cxf.binding.soap.SoapVersion; +import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.helpers.DOMUtils; +import org.apache.cxf.jaxws.context.WrappedMessageContext; +import org.apache.cxf.staxutils.StaxUtils; +import org.apache.cxf.ws.addressing.ReferenceParametersType; +import org.apache.cxf.ws.transfer.Representation; +import org.apache.cxf.ws.transfer.shared.faults.UnknownResource; + +/** + * In memory implementation for ResourceManager interface. + */ +public class MemoryResourceManager implements ResourceManager { + + public static final String REF_NAMESPACE = "http://cxf.apache.org/rt/ws/transfer/MemoryResourceManager"; + + public static final String REF_LOCAL_NAME = "uuid"; + + private static final Logger LOG = LogUtils.getL7dLogger(MemoryResourceManager.class); + + protected Map<String, String> storage; + + @Resource + private WebServiceContext context; + + public MemoryResourceManager() { + storage = new HashMap<String, String>(); + } + + @Override + public Representation get(ReferenceParametersType ref) { + String uuid = getUUID(ref); + if (!storage.containsKey(uuid)) { + throw new UnknownResource(); + } + String resource = storage.get(uuid); + if (resource.isEmpty()) { + return new Representation(); + } else { + Document doc = null; + try { + doc = StaxUtils.read(new StringReader(storage.get(uuid))); + } catch (XMLStreamException e) { + LOG.severe(e.getLocalizedMessage()); + throw new SoapFault("Internal Error", getSoapVersion().getReceiver()); + } + Representation representation = new Representation(); + representation.setAny(doc.getDocumentElement()); + return representation; + } + } + + @Override + public void delete(ReferenceParametersType ref) { + String uuid = getUUID(ref); + if (!storage.containsKey(uuid)) { + throw new UnknownResource(); + } + storage.remove(uuid); + } + + @Override + public void put(ReferenceParametersType ref, Representation newRepresentation) { + String uuid = getUUID(ref); + if (!storage.containsKey(uuid)) { + throw new UnknownResource(); + } + Element representationEl = (Element) newRepresentation.getAny(); + if (representationEl == null) { + storage.put(uuid, ""); + } else { + storage.put(uuid, StaxUtils.toString(representationEl)); + } + } + + @Override + public ReferenceParametersType create(Representation initRepresentation) { + // Store xmlResource + String uuid = UUID.randomUUID().toString(); + Element representationEl = (Element) initRepresentation.getAny(); + if (representationEl == null) { + storage.put(uuid, ""); + } else { + storage.put(uuid, StaxUtils.toString(representationEl)); + } + + Element uuidEl = DOMUtils.createDocument().createElementNS(REF_NAMESPACE, REF_LOCAL_NAME); + uuidEl.setTextContent(uuid); + + // Create referenceParameter + ReferenceParametersType refParam = new ReferenceParametersType(); + refParam.getAny().add(uuidEl); + return refParam; + } + + private String getUUID(ReferenceParametersType ref) { + for (Object object : ref.getAny()) { + if (object instanceof JAXBElement) { + JAXBElement<?> element = (JAXBElement<?>) object; + QName qName = element.getName(); + if ( + REF_NAMESPACE.equals(qName.getNamespaceURI()) + && REF_LOCAL_NAME.equals(qName.getLocalPart())) { + return (String) element.getValue(); + } + } else if (object instanceof Element) { + Element element = (Element) object; + if ( + REF_NAMESPACE.equals(element.getNamespaceURI()) + && REF_LOCAL_NAME.equals(element.getLocalName())) { + return element.getTextContent(); + } + } + } + throw new UnknownResource(); + } + + private SoapVersion getSoapVersion() { + WrappedMessageContext wmc = (WrappedMessageContext) context.getMessageContext(); + SoapMessage message = (SoapMessage) wmc.getWrappedMessage(); + return message.getVersion(); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/manager/ResourceManager.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/manager/ResourceManager.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/manager/ResourceManager.java new file mode 100644 index 0000000..7dbc6ac --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/manager/ResourceManager.java @@ -0,0 +1,59 @@ +/** + * 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 org.apache.cxf.ws.transfer.manager; + +import org.apache.cxf.ws.addressing.ReferenceParametersType; +import org.apache.cxf.ws.transfer.Representation; + +/** + * Interface for managing resource representations. + */ +public interface ResourceManager { + + /** + * Returns Representation object given by reference parameter. + * @param ref Reference parameter returned by create method. + * @return Representation object containing the XML resource. + * @see ResourceManager#create(org.apache.cxf.ws.transfer.Representation) + */ + Representation get(ReferenceParametersType ref); + + /** + * Deletes Representation object given by reference parameter. + * @param ref Reference parameter returned by create method. + * @see ResourceManager#create(org.apache.cxf.ws.transfer.Representation) + */ + void delete(ReferenceParametersType ref); + + /** + * Replaces Representation object given by reference parameter with newRepresentation. + * @param ref Reference parameter returned by create method. + * @param newRepresentation New Representation object, which will replace the old one. + * @see ResourceManager#create(org.apache.cxf.ws.transfer.Representation) + */ + void put(ReferenceParametersType ref, Representation newRepresentation); + + /** + * Creates new Representation object from initRepresenation. + * @param initRepresentation Representation object containing initial XML resource. + * @return Reference parameter for newly created Representation object. + */ + ReferenceParametersType create(Representation initRepresentation); +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/resource/Resource.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/resource/Resource.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/resource/Resource.java new file mode 100644 index 0000000..3280e39 --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/resource/Resource.java @@ -0,0 +1,101 @@ +/** + * 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 org.apache.cxf.ws.transfer.resource; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebResult; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; +import javax.xml.ws.Action; +import javax.xml.ws.soap.Addressing; +import org.apache.cxf.ws.transfer.Delete; +import org.apache.cxf.ws.transfer.DeleteResponse; +import org.apache.cxf.ws.transfer.Get; +import org.apache.cxf.ws.transfer.GetResponse; +import org.apache.cxf.ws.transfer.Put; +import org.apache.cxf.ws.transfer.PutResponse; +import org.apache.cxf.ws.transfer.shared.TransferConstants; + +/** + * The interface definition of a Resource web service, according to the specification. + */ +@WebService(targetNamespace = TransferConstants.TRANSFER_2011_03_NAMESPACE, + name = TransferConstants.NAME_RESOURCE) +@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) +@Addressing(enabled = true, required = true) +public interface Resource { + + @Action( + input = TransferConstants.ACTION_GET, + output = TransferConstants.ACTION_GET_RESPONSE) + @WebMethod(operationName = TransferConstants.NAME_OPERATION_GET) + @WebResult( + name = TransferConstants.NAME_MESSAGE_GET_RESPONSE, + targetNamespace = TransferConstants.TRANSFER_2011_03_NAMESPACE, + partName = "Body" + ) + GetResponse get( + @WebParam( + name = TransferConstants.NAME_MESSAGE_GET, + targetNamespace = TransferConstants.TRANSFER_2011_03_NAMESPACE, + partName = "Body" + ) + Get body + ); + + @Action( + input = TransferConstants.ACTION_DELETE, + output = TransferConstants.ACTION_DELETE_RESPONSE + ) + @WebMethod(operationName = TransferConstants.NAME_OPERATION_DELETE) + @WebResult( + name = TransferConstants.NAME_MESSAGE_DELETE_RESPONSE, + targetNamespace = TransferConstants.TRANSFER_2011_03_NAMESPACE, + partName = "Body" + ) + DeleteResponse delete( + @WebParam( + name = TransferConstants.NAME_MESSAGE_DELETE, + targetNamespace = TransferConstants.TRANSFER_2011_03_NAMESPACE, + partName = "Body" + ) + Delete body + ); + + @Action( + input = TransferConstants.ACTION_PUT, + output = TransferConstants.ACTION_PUT_RESPONSE + ) + @WebMethod(operationName = TransferConstants.NAME_OPERATION_PUT) + @WebResult( + name = TransferConstants.NAME_MESSAGE_PUT_RESPONSE, + targetNamespace = TransferConstants.TRANSFER_2011_03_NAMESPACE, + partName = "Body" + ) + PutResponse put( + @WebParam( + name = TransferConstants.NAME_MESSAGE_PUT, + targetNamespace = TransferConstants.TRANSFER_2011_03_NAMESPACE, + partName = "Body" + ) + Put body + ); +} http://git-wip-us.apache.org/repos/asf/cxf/blob/517ef67f/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/resource/ResourceLocal.java ---------------------------------------------------------------------- diff --git a/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/resource/ResourceLocal.java b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/resource/ResourceLocal.java new file mode 100644 index 0000000..49333d6 --- /dev/null +++ b/rt/ws/transfer/src/main/java/org/apache/cxf/ws/transfer/resource/ResourceLocal.java @@ -0,0 +1,191 @@ +/** + * 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 org.apache.cxf.ws.transfer.resource; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.xml.ws.WebServiceContext; +import org.apache.cxf.jaxws.context.WrappedMessageContext; +import org.apache.cxf.ws.addressing.AddressingProperties; +import org.apache.cxf.ws.addressing.JAXWSAConstants; +import org.apache.cxf.ws.addressing.ReferenceParametersType; +import org.apache.cxf.ws.transfer.Delete; +import org.apache.cxf.ws.transfer.DeleteResponse; +import org.apache.cxf.ws.transfer.Get; +import org.apache.cxf.ws.transfer.GetResponse; +import org.apache.cxf.ws.transfer.Put; +import org.apache.cxf.ws.transfer.PutResponse; +import org.apache.cxf.ws.transfer.Representation; +import org.apache.cxf.ws.transfer.dialect.Dialect; +import org.apache.cxf.ws.transfer.dialect.fragment.FragmentDialect; +import org.apache.cxf.ws.transfer.dialect.fragment.FragmentDialectConstants; +import org.apache.cxf.ws.transfer.manager.ResourceManager; +import org.apache.cxf.ws.transfer.shared.faults.UnknownDialect; +import org.apache.cxf.ws.transfer.validationtransformation.ResourceTypeIdentifier; +import org.apache.cxf.ws.transfer.validationtransformation.ValidAndTransformHelper; + +/** + * Implementation of the Resource interface for resources, which are created locally. + * @see org.apache.cxf.ws.transfer.resourcefactory.resolver.ResourceResolver + */ +public class ResourceLocal implements Resource { + + @javax.annotation.Resource + protected WebServiceContext context; + + protected ResourceManager manager; + + protected List<ResourceTypeIdentifier> resourceTypeIdentifiers; + + protected Map<String, Dialect> dialects; + + public ResourceLocal() { + dialects = new HashMap<String, Dialect>(); + dialects.put(FragmentDialectConstants.FRAGMENT_2011_03_IRI, new FragmentDialect()); + } + + public ResourceManager getManager() { + return manager; + } + + public void setManager(ResourceManager manager) { + this.manager = manager; + } + + public List<ResourceTypeIdentifier> getResourceTypeIdentifiers() { + if (resourceTypeIdentifiers == null) { + resourceTypeIdentifiers = new ArrayList<>(); + } + return resourceTypeIdentifiers; + } + + public void setResourceTypeIdentifiers(List<ResourceTypeIdentifier> resourceTypeIdentifiers) { + this.resourceTypeIdentifiers = resourceTypeIdentifiers; + } + + /** + * Register Dialect object for URI. + * @param iri + * @param dialect + */ + public void registerDialect(String iri, Dialect dialect) { + if (dialects.containsKey(iri)) { + throw new IllegalArgumentException(String.format("IRI \"%s\" is already registered", iri)); + } + dialects.put(iri, dialect); + } + + /** + * Unregister dialect URI. + * @param iri + */ + public void unregisterDialect(String iri) { + if (!dialects.containsKey(iri)) { + throw new IllegalArgumentException(String.format("IRI \"%s\" is not registered", iri)); + } + dialects.remove(iri); + } + + @Override + public GetResponse get(Get body) { + // Getting reference paramaters + AddressingProperties addrProps = (AddressingProperties) ((WrappedMessageContext) context + .getMessageContext()).getWrappedMessage() + .getContextualProperty(JAXWSAConstants.ADDRESSING_PROPERTIES_INBOUND); + ReferenceParametersType refParams = addrProps + .getToEndpointReference() + .getReferenceParameters(); + GetResponse response = new GetResponse(); + // Getting representation from the ResourceManager + Representation representation = manager.get(refParams); + // Dialect processing + if (body.getDialect() != null && !body.getDialect().isEmpty()) { + if (dialects.containsKey(body.getDialect())) { + Dialect dialect = dialects.get(body.getDialect()); + // Send fragment of resource instead it's representation. + response.getAny().add(dialect.processGet(body, representation)); + } else { + throw new UnknownDialect(); + } + } else { + // Send representation obtained from ResourceManager. + response.setRepresentation(representation); + } + return response; + } + + @Override + public DeleteResponse delete(Delete body) { + // Getting reference paramaters + AddressingProperties addrProps = (AddressingProperties) ((WrappedMessageContext) context + .getMessageContext()).getWrappedMessage() + .getContextualProperty(JAXWSAConstants.ADDRESSING_PROPERTIES_INBOUND); + ReferenceParametersType refParams = addrProps + .getToEndpointReference() + .getReferenceParameters(); + boolean delete = true; + // Dialect processing + if (body.getDialect() != null && !body.getDialect().isEmpty()) { + if (dialects.containsKey(body.getDialect())) { + Dialect dialect = dialects.get(body.getDialect()); + delete = dialect.processDelete(body, manager.get(refParams)); + } else { + throw new UnknownDialect(); + } + } + if (delete) { + manager.delete(refParams); + } + return new DeleteResponse(); + } + + @Override + public PutResponse put(Put body) { + // Getting reference paramaters + AddressingProperties addrProps = (AddressingProperties) ((WrappedMessageContext) context + .getMessageContext()).getWrappedMessage() + .getContextualProperty(JAXWSAConstants.ADDRESSING_PROPERTIES_INBOUND); + ReferenceParametersType refParams = addrProps + .getToEndpointReference() + .getReferenceParameters(); + // Getting representation from the ResourceManager + Representation storedRepresentation = manager.get(refParams); + // Getting representation from the incoming SOAP message. This representation will be stored. + Representation putRepresentation = body.getRepresentation(); + // Dialect processing + if (body.getDialect() != null && !body.getDialect().isEmpty()) { + if (dialects.containsKey(body.getDialect())) { + Dialect dialect = dialects.get(body.getDialect()); + putRepresentation = dialect.processPut(body, storedRepresentation); + } else { + throw new UnknownDialect(); + } + } + ValidAndTransformHelper.validationAndTransformation( + resourceTypeIdentifiers, putRepresentation, storedRepresentation); + manager.put(refParams, putRepresentation); + PutResponse response = new PutResponse(); + response.setRepresentation(putRepresentation); + return response; + } + +}