/*=============================================================================*
* Copyright 2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*=============================================================================*/
package org.apache.ws.resource.metadataexchange.v2004_09.porttype.impl;
import org.apache.ws.resource.AbstractPortType;
import org.apache.ws.resource.ResourceContext;
import org.apache.ws.resource.metadataexchange.v2004_09.MetadataExchangeConstants;
import org.apache.ws.resource.metadataexchange.v2004_09.porttype.MetadataExchangePortType;
import org.apache.ws.resource.properties.NamespaceVersionHolder;
import org.apache.ws.resource.properties.v2004_11.impl.NamespaceVersionHolderImpl;
import org.apache.ws.util.XmlBeanUtils;
import org.apache.ws.util.jndi.tools.MetadataConfig;
import org.apache.ws.util.soap.SoapClient;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.xmlsoap.schemas.soap.envelope.Envelope;
import org.xmlsoap.schemas.soap.envelope.EnvelopeDocument;
import org.xmlsoap.schemas.soap.envelope.Header;
import org.xmlsoap.schemas.ws.x2004.x08.addressing.AttributedURI;
import org.xmlsoap.schemas.ws.x2004.x08.addressing.EndpointReferenceType;
import org.xmlsoap.schemas.ws.x2004.x09.mex.AnyXmlType;
import org.xmlsoap.schemas.ws.x2004.x09.mex.GetMetadataDocument;
import org.xmlsoap.schemas.ws.x2004.x09.mex.LocationDocument;
import org.xmlsoap.schemas.ws.x2004.x09.mex.MetadataDocument;
import org.xmlsoap.schemas.ws.x2004.x09.mex.MetadataReferenceDocument;
import org.xmlsoap.schemas.ws.x2004.x09.mex.MetadataSectionDocument;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* An implementation of the WS-MEX MetadataExchange portType.
*
* @author Sal Campana
*/
public class MetadataExchangePortTypeImpl extends AbstractPortType implements MetadataExchangePortType
{
private static final NamespaceVersionHolder NAMESPACE_SET = new NamespaceVersionHolderImpl();
/**
* Creates a new {@link AbstractPortType} object.
*
* @param resourceContext
*/
public MetadataExchangePortTypeImpl(ResourceContext resourceContext)
{
super(resourceContext);
}
/**
* WS-MetadataExchange GetMetadata operation.
*
* @param request
* @return MetadataDocument response document
*/
public MetadataDocument getMetadata(GetMetadataDocument request)
{ //todo deal with setting Action for responses...
MetadataConfig metadataConfig = getMetadataConfigFromJNDI();
//prep the response
MetadataDocument responseDoc = createMetadataResponseDoc();
MetadataDocument.Metadata responseMetadata = responseDoc.addNewMetadata();
//get the values from the request
GetMetadataDocument.GetMetadata requestMetadata = request.getGetMetadata();
String dialect = requestMetadata.getDialect();
String identifier = requestMetadata.getIdentifier();
//get the metatdata from the config
// the map is keyed on dialect and keyed to a List of metadata
// this allows you to build a metadata section per dialect
Map metadataMap = metadataConfig.getMetadata(dialect, identifier);
//iterate the returned set and add metadata sections
Iterator iterator = metadataMap.keySet().iterator();
while (iterator.hasNext())
{
String dialectKey = (String) iterator.next();
//get the list of metatadata for this dialect
List metadataList = (List) metadataMap.get(dialectKey);
for (int i = 0; i < metadataList.size(); i++)
{
//create a new metadata section
MetadataSectionDocument.MetadataSection metadataSection = responseMetadata.addNewMetadataSection();
Object data = metadataList.get(i);
metadataSection.setDialect(dialectKey);
if(identifier != null && !"".equals(identifier))
{
metadataSection.setIdentifier(identifier);
}
/** Determine type of metadata to add **/
if(data instanceof MetadataReferenceDocument)
{
//adds a MetadataReference for locating the metadata
metadataSection.setMetadataReference((EndpointReferenceType) data);
}
else if (data instanceof LocationDocument)
{
//adds a Location for locating the metadata
metadataSection.setLocation(((LocationDocument) data).getLocation());
}
else
{
//else its the metadata document and must be added as a child for the "any"
XmlBeanUtils.addChildElement(metadataSection, (XmlObject) data);
}
}
}
return responseDoc;
}
private MetadataConfig getMetadataConfigFromJNDI()
{
String metadataJndiContextName = getMetadataJndiContextName();
try
{
return (MetadataConfig) new InitialContext().lookup(metadataJndiContextName);
}
catch ( NamingException ne )
{
throw new RuntimeException( "Unable to retrieve WS-MetadataExchange configuration.", ne);
}
}
/**
* Returns the JNDI Contrext name for looking up the metadata
*
* @return
*/
private String getMetadataJndiContextName()
{
return org.apache.ws.resource.JndiConstants.CONTEXT_NAME_SERVICES + "/" + getResourceContext().getServiceName() + "/" + org.apache.ws.resource.JndiConstants.ATOMIC_METADATA_CONTEXT;
}
/**
* Creates the response object for a GetMetadata request
*
* @return empty MetadataDocument
*/
private MetadataDocument createMetadataResponseDoc()
{
MetadataDocument metadataDocument = MetadataDocument.Factory.newInstance();
return metadataDocument;
}
/**
* WS-MetadataExchange Get operation.
*
* @return AnyXmlType response document.
*/
public AnyXmlType get()
{
AnyXmlType anyXmlType = AnyXmlType.Factory.newInstance();
MetadataConfig metadataConfig = getMetadataConfigFromJNDI();
//get all the registered metadata
Map allMetadata = metadataConfig.getAllMetadata();
Iterator iterator = allMetadata.values().iterator();
while (iterator.hasNext())
{
List metadataList = (List) iterator.next();
for (int i = 0; i < metadataList.size(); i++)
{
Object metadata = metadataList.get(i);
/** Determine type of metadata to add **/
if(metadata instanceof MetadataReferenceDocument)
{
//must load actual metadata using MetadataReference
try
{
metadata = loadMetadataFromEPR(((MetadataReferenceDocument) metadata).getMetadataReference());
}
catch (Exception e)
{
throw new RuntimeException( "Unable to retrieve metadata from the configured EPR: " + metadata, e);
}
}
else if (metadata instanceof LocationDocument)
{
try
{
metadata = loadMetadataFromURL(((LocationDocument) metadata).getLocation());
}
catch (Exception e)
{
//not sure if we should ignore a problem and send the rest...
throw new RuntimeException( "Unable to retrieve metadata from the configured URL: " + ((LocationDocument) metadata).getLocation(), e);
}
}
XmlBeanUtils.addChildElement(anyXmlType, (XmlObject) metadata);
}
}
return anyXmlType;
}
/**
* Loads metadata off of a URL.
*
* @param s
* @return
* @throws IOException
* @throws XmlException
*/
private Object loadMetadataFromURL(String s) throws IOException, XmlException
{
return XmlObject.Factory.parse(new URL(s));
}
/**
* Loads metadata off of an EPR.
*
* @param epr
* @return
* @throws IOException
* @throws URISyntaxException
* @throws XmlException
*/
private Object loadMetadataFromEPR(EndpointReferenceType epr) throws IOException, URISyntaxException, XmlException
{
String address = epr.getAddress().getStringValue();
//send WS-MEX Get request
EnvelopeDocument envelope = buildSoapEnvelopeForGet(address, epr);
String response = SoapClient.sendRequest(new URL(address),envelope.newInputStream(),new URI(MetadataExchangeConstants.ACTION_GET));
return XmlObject.Factory.parse(response);
}
/**
* Builds a SOAP Envelope based on the EPR and makes a request to retrieve the metadata.
*
* @param address
* @param endpointReferenceType
* @return The SOAP Envelope for making a request.
*/
private EnvelopeDocument buildSoapEnvelopeForGet(String address, EndpointReferenceType endpointReferenceType)
{
EnvelopeDocument envelopeDocument = EnvelopeDocument.Factory.newInstance();
Envelope envelope = envelopeDocument.addNewEnvelope();
envelope.addNewBody();
Header header = envelope.addNewHeader();
XmlObject toElem;
XmlObject actionElem;
org.xmlsoap.schemas.ws.x2004.x08.addressing.ToDocument toDoc = org.xmlsoap.schemas.ws.x2004.x08.addressing.ToDocument.Factory.newInstance();
AttributedURI attributedURI = toDoc.addNewTo();
attributedURI.setStringValue(address);
toElem = toDoc;
org.xmlsoap.schemas.ws.x2004.x08.addressing.ActionDocument actionDoc = org.xmlsoap.schemas.ws.x2004.x08.addressing.ActionDocument.Factory.newInstance();
AttributedURI actionType = actionDoc.addNewAction();
actionType.setStringValue( MetadataExchangeConstants.ACTION_GET );
actionElem = actionDoc;
XmlBeanUtils.addChildElement( header, toElem );
XmlBeanUtils.addChildElement( header, actionElem );
if (endpointReferenceType.getReferenceProperties() != null)
{
XmlObject[] refPropElems = XmlBeanUtils.getChildElements(endpointReferenceType.getReferenceProperties());
for (int i = 0; i < refPropElems.length; i++)
{
XmlBeanUtils.addChildElement(header, refPropElems[i]);
}
}
return envelopeDocument;
}
protected NamespaceVersionHolder getNamespaceSet()
{
return NAMESPACE_SET;
}
}