/*
 * This source code is made available under the terms of the
 * Common Public License Version 1.0 distibuted along with the
 * source code package.
 */
package de.uka.cmtm.serviceregistry.publish.uddi.wsdls;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.wsdl.Operation;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.xml.namespace.QName;

import org.uddi4j.UDDIException;
import org.uddi4j.client.UDDIProxy;
import org.uddi4j.datatype.tmodel.TModel;
import org.uddi4j.response.AuthToken;
import org.uddi4j.transport.TransportException;
import org.uddi4j.util.CategoryBag;
import org.uddi4j.util.KeyedReference;

import de.uka.cmtm.serviceregistry.publish.uddi.UddiTModels;
import de.uka.cmtm.serviceregistry.publish.uddi.UddiUtils;
import de.uka.cmtm.serviceregistry.publish.uddi.WsdlPublisher;
import de.uka.cmtm.serviceregistry.publish.uddi.wsdl.WsdlPublisherV01_08;

/**
 * This WsdlPublisher can publish WSDL files in UDDI following the UDDI.org
 * best practices 1.08 mapping. In addition it publishes ontology references to
 * all service profiles implemented by the PortTypes in use by the service in
 * the services category bag.
 * 
 * @author tilmann
 */
public class SaWsdlPublisherV01_08 extends WsdlPublisherV01_08 implements
		WsdlPublisher {

	/**
	 * The name of the SA-WSDL modelReference attribute.
	 */
	private static final QName MODEL_REFERENCE_QNAME = new QName(
			"http://www.w3.org/2002/ws/sawsdl/spec/sawsdl#", "modelReference");

	private String upperServiceOntologyUrl;

	private UddiUtils uddiUtils;

	/**
	 * Creates a new SaWsdlPublisherV01_08
	 * 
	 * @param uddiProxy
	 *            the UDDIProxy to be used
	 * @param authToken
	 *            the UDDI credentials to be used
	 * @param upperServiceOntologyUrl
	 *            the URL of the upper service ontology
	 */
	public SaWsdlPublisherV01_08(UDDIProxy uddiProxy, AuthToken authToken,
			String upperServiceOntologyUrl) {
		super(uddiProxy, authToken);
		this.uddiUtils = new UddiUtils(uddiProxy, authToken);
		this.upperServiceOntologyUrl = upperServiceOntologyUrl;
	}

	/**
	 * This hook adds the references to the implemented service profiles to the
	 * services category bag.
	 * 
	 * @param categoryBag
	 *            here can KeyedReferences be added
	 * @param service
	 *            the Service that is published
	 * @throws UDDIException
	 * @throws TransportException
	 */
	@Override
	protected void addServiceCategoryBagKeyedReferences(
			CategoryBag categoryBag, Service service) throws UDDIException,
			TransportException {

		Set<String> profiles = new HashSet<String>();

		// Traverse all Ports of the service
		Collection<Port> ports = service.getPorts().values();
		for (Port port : ports) {
			Collection<Operation> operations = port.getBinding().getPortType()
					.getOperations();

			// Traverse all operation in the port types
			for (Operation operation : operations) {
				Object attr = operation
						.getExtensionAttribute(MODEL_REFERENCE_QNAME);

				// Add profile if attribute found
				if (attr != null)
					profiles.add(attr.toString());
			}
		}

		// Cue keyed references for every service profile found
		if (!profiles.isEmpty()) {
			TModel serviceProfileTModel = publishServiceProfileTModel();

			for (String profile : profiles) {
				KeyedReference kRef = new KeyedReference();
				kRef.setTModelKey(serviceProfileTModel.getTModelKey());
				kRef.setKeyName("ServiceProfile");
				kRef.setKeyValue(profile);
				categoryBag.add(kRef);
			}
		}

	}

	/**
	 * Search or publish the TModel used for the service provile references.
	 * 
	 * @return the found/published TModel
	 * @throws UDDIException
	 * @throws TransportException
	 */
	private TModel publishServiceProfileTModel() throws UDDIException,
			TransportException {

		CategoryBag cBag = new CategoryBag();
		KeyedReference kRef = new KeyedReference();
		kRef.setTModelKey(UddiTModels.TYPES.getKey());
		kRef.setKeyName(UddiTModels.TYPES.getName());
		kRef.setKeyValue("categorization");
		cBag.add(kRef);
		return uddiUtils.publishTModel(UddiTModels.SERVICE_PROFILE.getName(),
				"Service Profile Reference", upperServiceOntologyUrl, cBag);
	}

}
