package org.sbolstandard.core.datatree;

import javax.xml.namespace.QName;

import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Static utilities for working with the datatree types.
 *
 *

 *   This provides factory methods for the creation of instances of all datatree types.
 *   It is designed to be statically imported and then used as if it were constructors, but without the "new" keyword.
 *

 *
 *

 *   In addition to the primary datatree types, this class has several nested types that provide type-safe
 *   representations of collections.
 *   This enables a very natural syntax for declaratively expressing nested data values.
 *

 *
 *

 *   Example use:
 *

 *

 * import static org.sbolstandard.core.datatree.Datatree.*;
 *
 * NamespaceBinding foaf = NamespaceBinding("http://xmlns.com/foaf/0.1/", "foaf");
 *
 * NamedProperty spidermanName = NamedProperty(foaf.withLocalPart("name"), "Peter Parker");
 *

 *
 * @author Matthew Pocock
 */
public final class Datatree
{
  // prevent instantiation
  private Datatree() {}

  /**
   * A list of top-level documents.
   *
   *

   *   Used by:
   *

   *

   *
{@link #DocumentRoot(org.sbolstandard.core.datatree.Datatree.NamespaceBindings, org.sbolstandard.core.datatree.Datatree.TopLevelDocuments)}

   *
{@link #DocumentRoot(org.sbolstandard.core.datatree.Datatree.TopLevelDocuments)}

   *

   *
   * @author Matthew Pocock
   * @param <N>  the name type of the documents
   */
  public interface TopLevelDocuments<N> {
    /**
     * Get the wrapped documents.
     *
     * @return the wrapped documents.
     */
    List<TopLevelDocument<N>> getDocuments();

    class Impl<N> implements TopLevelDocuments<N> {
      private final List<TopLevelDocument<N>> documents;

      Impl(List<TopLevelDocument<N>> documents) {
        if (documents == null)
          throw new NullPointerException("");
        this.documents = documents;
      }

      @Override
      public List<TopLevelDocument<N>> getDocuments() {
        return documents;
      }

      @Override
      public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Impl impl = (Impl) o;

        return documents.equals(impl.documents);

      }

      @Override
      public int hashCode() {
        return documents.hashCode();
      }

      @Override
      public String toString() {
        return "TopLevelDocuments{" +
                "documents=" + documents +
                '}';
      }
    }
  }

  /**
   * Factory for {@link TopLevelDocuments}.
   *
   *

   *   Used by the {@link DocumentRoot} factory methods.
   *

   *
   * @param documents   the documents to wrap
   * @param <N>         the property name type
   * @return  a new TopLevelDocuments that wraps up documents
   */
  @SafeVarargs
  public static <N> TopLevelDocuments<N> TopLevelDocuments(TopLevelDocument<N> ... documents) {
    return TopLevelDocuments(Arrays.asList(documents));
  }

  /**
   * Factory for {@link TopLevelDocuments}.
   *
   *

   *   Used by the {@link DocumentRoot} factory methods.
   *

   *
   * @param documents   the documents to wrap
   * @param <N>         the property name type
   * @return  a new TopLevelDocuments that wraps up documents
   */
  public static <N> TopLevelDocuments<N> TopLevelDocuments(final List<TopLevelDocument<N>> documents) {
    return new TopLevelDocuments.Impl<>(documents);
  }

  /**
   * A list of {@link NamespaceBinding}s.
   *
   *

   *   Used by:
   *

   *

   *
{@link #TopLevelDocument(org.sbolstandard.core.datatree.Datatree.NamespaceBindings, Object, java.net.URI, org.sbolstandard.core.datatree.Datatree.NamedProperties)}

   *
{@link #NestedDocument(org.sbolstandard.core.datatree.Datatree.NamespaceBindings, Object, java.net.URI, org.sbolstandard.core.datatree.Datatree.NamedProperties)}

   *

   *
   * @author Matthew Pocock
   */
  public interface NamespaceBindings {
    List<NamespaceBinding> getBindings();

    class Impl implements NamespaceBindings {
      private final List<NamespaceBinding> bindings;

      Impl(List<NamespaceBinding> bindings) {
        if(bindings == null)
          throw new NullPointerException("Can't create a NamespaceBinding instance with null bindings");
        this.bindings = bindings;
      }

      @Override
      public List<NamespaceBinding> getBindings() {
        return bindings;
      }

      @Override
      public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Impl impl = (Impl) o;

        return bindings.equals(impl.bindings);

      }

      @Override
      public int hashCode() {
        return bindings.hashCode();
      }

      @Override
      public String toString() {
        return "NamespaceBindings{" +
                "bindings=" + bindings +
                '}';
      }
    }

  }

  /**
   * Factory for {@link NamespaceBindings}.
   *
   *

   *   Used by {@link org.sbolstandard.core.datatree.TopLevelDocument} and {@link org.sbolstandard.core.datatree.NestedDocument}
   *   factory methods.
   *

   *
   * @param bindings  list of bindings
   * @return    a new NamespaceBindnigs wrapping the bindings list
   * @throws NullPointerException if bindings is null
   */
  public static NamespaceBindings NamespaceBindings(final List<NamespaceBinding> bindings) {
    return new NamespaceBindings.Impl(bindings);
  }

  /**
   * Factory for {@link NamespaceBindings}.
   *
   *

   *   Used by {@link org.sbolstandard.core.datatree.TopLevelDocument} and {@link org.sbolstandard.core.datatree.NestedDocument}
   *   factory methods.
   *

   *
   * @param bindings  bindings
   * @return    a new NamespaceBindnigs wrapping the bindings
   */
  public static NamespaceBindings NamespaceBindings(final NamespaceBinding ...bindings) {
    return NamespaceBindings(Arrays.asList(bindings));
  }

  /**
   * A list of {@link NamedProperty}s.
   *
   *
Used by

   *

   *
{@link #TopLevelDocument(Object, java.net.URI, org.sbolstandard.core.datatree.Datatree.NamedProperties)}

   *
{@link #TopLevelDocument(org.sbolstandard.core.datatree.Datatree.NamespaceBindings, Object, java.net.URI, org.sbolstandard.core.datatree.Datatree.NamedProperties)}

   *
{@link #NestedDocument(Object, java.net.URI, org.sbolstandard.core.datatree.Datatree.NamedProperties)}

   *
{@link #NestedDocument(org.sbolstandard.core.datatree.Datatree.NamespaceBindings, Object, java.net.URI, org.sbolstandard.core.datatree.Datatree.NamedProperties)}

   *

   *
   *

   *   The P parameter is used to restrict the property value range to either all possible values, or to literals only.
   *

   *
   * @author Matthew Pocock
   * @param <N>   the property name type
   */
  public interface NamedProperties<N> {
    List<NamedProperty<N>> getProperties();

    class Impl<N> implements NamedProperties<N> {
        private final List<NamedProperty<N>> properties;

        Impl(List<NamedProperty<N>> properties) {
          if(properties == null)
            throw new NullPointerException("Can't create a NamedProperties with null properties");
          this.properties = properties;
        }

        @Override
        public List<NamedProperty<N>> getProperties() {
          return properties;
        }

      @Override
      public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Impl<?> impl = (Impl<?>) o;

        return properties.equals(impl.properties);

      }

      @Override
      public int hashCode() {
        return properties.hashCode();
      }

      @Override
      public String toString() {
        return "NamedProperties{" +
                "properties=" + properties +
                '}';
      }
    }
  }

  /**
   * Factory for {@link NamedProperties}.
   *
   *

   *   Used by {@link org.sbolstandard.core.datatree.NestedDocument}
   *   factory methods.
   *

   *
   * @param properties  properties
   * @return    a new NamedProperties wrapping the properties
   */
  @SafeVarargs
  public static <N> NamedProperties<N> NamedProperties(final NamedProperty<N> ... properties) {
    return NamedProperties(Arrays.asList(properties));
  }

  /**
   * Factory for {@link NamedProperties}.
   *
   *

   *   Used by {@link org.sbolstandard.core.datatree.NestedDocument}
   *   factory methods.
   *

   *
   * @param properties  properties list
   * @return    a new NamedProperties wrapping the properties
   */
  public static <N> NamedProperties<N> NamedProperties(final List<NamedProperty<N>> properties) {
    return new NamedProperties.Impl<>(properties);
  }

  /**
   * Factory for {@link TopLevelDocument}.
   *
   *

   *   This builds a new TopLevelDocument using the supplied data.
   *

   *
   * @param type        the type of the document
   * @param identity    the identity of the document
   * @param properties  the property list of the document
   * @param <N>         the property name type
   * @return  a new TopLevelDocument instance
   */
  public static <N> TopLevelDocument<N> TopLevelDocument(final N type,
                                                         final URI identity,
                                                         final NamedProperties<N> properties) {
    return TopLevelDocument(NamespaceBindings(), type, identity, properties);
  }

  /**
   * Factory for {@link TopLevelDocument}.
   *
   *

   *   This builds a new TopLevelDocument using the supplied data.
   *

   *
   * @param bindings    the namespace bindings
   * @param type        the type of the document
   * @param identity    the identity of the document
   * @param <N>         the property name type
   * @return  a new TopLevelDocument instance
   */
  public static <N> TopLevelDocument<N> TopLevelDocument(final NamespaceBindings bindings,
                                                         final N type,
                                                         final URI identity) {
    return TopLevelDocument(bindings, type, identity, Datatree.<N>NamedProperties());
  }

  /**
   * Factory for {@link TopLevelDocument}.
   *
   *

   *   This builds a new TopLevelDocument using the supplied data.
   *

   *
   * @param bindings    the namespace bindings
   * @param type        the type of the document
   * @param identity    the identity of the document
   * @param properties  the property list of the document
   * @param <N>         the property name type
   * @return  a new TopLevelDocument instance
   */
  public static <N> TopLevelDocument<N> TopLevelDocument(final NamespaceBindings bindings,
                                                         final N type,
                                                         final URI identity,
                                                         final NamedProperties<N> properties) {
    return new TopLevelDocument.Impl<>(
            bindings.getBindings(),
            type,
            identity,
            properties.getProperties());
  }

  /**
   * Factory for {@link NestedDocument}.
   *
   *

   * This builds a new NestedDocument using the supplied data.
   *

   *
   * @param type        the type of the document
   * @param identity    the identity of the document
   * @param properties  the property list of the document
   * @param <N>         the property name type
   * @return  a new TopLevelDocument instance
   */
  public static <N> NestedDocument<N> NestedDocument(final N type,
                                                     final URI identity,
                                                     final NamedProperties<N> properties) {
    return NestedDocument(NamespaceBindings(), type, identity, properties);
  }

  /**
   * Factory for {@link NestedDocument}.
   *
   *

   * This builds a new NestedDocument using the supplied data.
   *

   *
   * @param bindings    the namespace bindings
   * @param type        the type of the document
   * @param identity    the identity of the document
   * @param <N>         the property name type
   * @return  a new TopLevelDocument instance
   */
  public static <N> NestedDocument<N> NestedDocument(final NamespaceBindings bindings,
                                                     final N type,
                                                     final URI identity)
  {
    return NestedDocument(bindings, type, identity, Datatree.<N>NamedProperties());
  }

  /**
   * Factory for {@link NestedDocument}.
   *
   *

   * This builds a new NestedDocument using the supplied data.
   *

   *
   * @param bindings    the namespace bindings
   * @param type        the type of the document
   * @param identity    the identity of the document
   * @param properties  the property list of the document
   * @param <N>         the property name type
   * @return  a new TopLevelDocument instance
   */
  public static <N> NestedDocument<N> NestedDocument(final NamespaceBindings bindings,
                                                     final N type,
                                                     final URI identity,
                                                     final NamedProperties<N> properties)
  {
    return new NestedDocument.Impl<>(
            bindings.getBindings(),
            type,
            identity,
            properties.getProperties());
  }

  /**
   * Factory for {@link DocumentRoot}.
   *
   *

   *   This builds a new DocumentRoot instance using the supplied data.
   *

   *
   * @param documents   the top-level documents
   * @param <N>         the property name type
   * @return  a new DocumentRoot instance
   */
  public static <N> DocumentRoot<N> DocumentRoot(final TopLevelDocuments<N> documents) {
    return DocumentRoot(NamespaceBindings(), documents);
  }

  /**
   * Factory for {@link DocumentRoot}.
   *
   *

   *   This builds a new DocumentRoot instance using the supplied data.
   *

   *
   * @param bindings    the namespace bindings
   * @param documents   the top-level documents
   * @param <N>         the property name type
   * @return  a new DocumentRoot instance
   */
  public static <N> DocumentRoot<N> DocumentRoot(
          final NamespaceBindings bindings,
          final TopLevelDocuments<N> documents) {
    return new DocumentRoot.Impl<>(bindings.getBindings(), documents.getDocuments());
  }

  /**
   * Create a value property from a literal value.
   *
   * @param name    the property name
   * @param value   the property value
   * @param <N>     the property name type
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> NamedProperty<N> NamedProperty(final N name, final PropertyValue<N> value) {
    return new NamedProperty.Impl<>(name, value);
  }

  /**
   * Create a value property from a string value.
   *
   * @param name    the property name
   * @param value   the property value
   * @param <N>     the property name type
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> NamedProperty<N> NamedProperty(final N name, final String value) {
    return NamedProperty(name, Datatree.<N>Literal(value));
  }

  /**
   * Create a value property from an int value.
   *
   * @param name    the property name
   * @param value   the property value
   * @param <N>     the property name type
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> NamedProperty<N> NamedProperty(final N name, final int value) {
    return NamedProperty(name, Datatree.<N>Literal(value));
  }

  /**
   * Create a value property from a URI value.
   *
   * @param name    the property name
   * @param value   the property value
   * @param <N>     the property name type
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> NamedProperty<N> NamedProperty(final N name, final URI value) {
    return NamedProperty(name, Datatree.<N>Literal(value));
  }

  /**
   * Create a value property from a Double value.
   *
   * @param name    the property name
   * @param value   the property value
   * @param <N>     the property name type
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> NamedProperty<N> NamedProperty(final N name, final Double value) {
    return NamedProperty(name, Datatree.<N>Literal(value));
  }

  /**
   * Create a value property from a Boolean value.
   *
   * @param name    the property name
   * @param value   the property value
   * @param <N>     the property name type
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> NamedProperty<N> NamedProperty(final N name, final Boolean value) {
    return NamedProperty(name, Datatree.<N>Literal(value));
  }

  /**
   * Create a value property from a nested document value.
   *
   * @param name    the property name
   * @param value   the property value
   * @param <N>     the property name type
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> NamedProperty<N> NamedProperty(final N name, final NestedDocument<N> value) {
    return new NamedProperty.Impl<>(name, value);
  }

  /**
   * Create a string literal.
   *
   * @param value   the property value
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> Literal.StringLiteral<N> Literal(final String value) {
    return new Literal.StringLiteral<>(value);
  }

  /**
   * Create an int literal.
   *
   * @param value   the property value
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> Literal.IntegerLiteral<N> Literal(final int value) {
    return new Literal.IntegerLiteral<>(value);
  }

  /**
   * Create a double literal.
   *
   * @param value   the property value
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> Literal.DoubleLiteral<N> Literal(final double value) {
    return new Literal.DoubleLiteral<>(value);
  }

  /**
   * Create a URI literal.
   *
   * @param value   the property value
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> Literal.UriLiteral<N> Literal(final URI value) {
    return new Literal.UriLiteral<>(value);
  }

  /**
   * Create a typed literal.
   *
   * @param value   the property value
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> Literal.TypedLiteral<N> Literal(final String value, final QName type) {
    return new Literal.TypedLiteral<>(value, type);
  }

  /**
   * Create a boolean literal.
   *
   * @param value   the property value
   * @return  a new NamedProperty with the supplied name and value
   */
  public static <N> Literal.BooleanLiteral<N> Literal(final boolean value) {
    return new Literal.BooleanLiteral<>(value);
  }

  /**
   * Create a namespace binding.
   *
   * @param namespaceUri  the namespace URI
   * @param prefix        the prefix
   * @return  a new namespace binding for the namespace and prefix
   */

  public static NamespaceBinding NamespaceBinding(String namespaceUri, String prefix) {
    return new NamespaceBinding(namespaceUri, prefix);
  }

  /**
   * Create a QName from a local part.
   *
   * @param localPart     the local part
   * @return  a QName with the supplied localPart
   */
  public static QName QName(String localPart) {
    return new QName(localPart);
  }

  /**
   * Create a QName from a namespace URI and local part.
   *
   * @param namespaceURI  the namespace URI
   * @param localPart     the local part
   * @return  a QName with the supplied namespace URI and localPart
   */
  public static QName QName(String namespaceURI, String localPart) {
    return new QName(namespaceURI, localPart);
  }

  /**
   * Create a QName from a namespace URI, local part and prefix.
   *
   * @param namespaceURI  the namespace URI
   * @param localPart     the local part
   * @param prefix        the prefix
   * @return  a QName with the supplied namespace URI, localPart and prefix
   */
  public static QName QName(String namespaceURI, String localPart, String prefix) {
    return new QName(namespaceURI, localPart, prefix);
  }
}


package org.sbolstandard.examples;

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;

import org.sbolstandard.core.datatree.DocumentRoot;
import org.sbolstandard.core.datatree.IdentifiableDocument;
import org.sbolstandard.core.datatree.Literal;
import org.sbolstandard.core.datatree.PropertyValue;
import org.sbolstandard.core.io.graphviz.DocumentStyler;
import org.sbolstandard.core.io.graphviz.GraphvizIo;
import org.sbolstandard.core.io.graphviz.Styler;
import org.sbolstandard.core.io.rdf.RdfTerms;

/**
 * Provides an example for exporting {@link DocumentRoot} objects using the JSON format.
 * In the example, {@link DocumentRoot} objects with both SBOL1.1.0 and SBOL2.0 data are exported in the GraphViz format.
 *
 * @author Matthew Pocock
 */
public class GraphvizExample
{
	/**
	 * Exports two example DocumentRoot objects (SBOL 1.1.0 and SBOL 2.0 objects) in the GraphViz format.
   *
   * @param args  command-line argument
   * @throws Exception if anything goes wrong
	 */
  public static void main( String[] args ) throws Exception
  {
    System.out.println("SBOL 1 example");
    write(new OutputStreamWriter(System.out), DataTreeCreator.makeDocument());

    System.out.println();
    System.out.println("----------------------------------------");
    System.out.println();

    System.out.println("SBOL 2 example");
    write(new OutputStreamWriter(System.out), DataTreeCreator.makeSBOL2Document());
  }

  private static void write(Writer stream, DocumentRoot<QName> document) throws Exception
  {
    PrintWriter writer = new PrintWriter(stream);
    GraphvizIo io = new GraphvizIo();

    io.setDocumentStyler(Styler.document.all(
            io.getDocumentStyler(),
            Styler.document.apply(Styler.mapMod.set("shape", "folder")),
            sbolPartTypeStyler));
    io.setLiteralStyler(Styler.literal.all(
            io.getLiteralStyler(),
            Styler.literal.apply(Styler.mapMod.set("shape", "note"))));

    io.createIoWriter(writer).write(document);
    writer.flush();
  }

  public static DocumentStyler sbolPartTypeStyler = new DocumentStyler() {
    @Override
    public void applyStyle(Map<String, String> styleMap, IdentifiableDocument<QName> document) {
      if(document.getType() == SbolTerms.dnaComponent) {
        for(PropertyValue<QName> pv : document.getPropertyValues(RdfTerms.rdfType)) {
          if (pv instanceof Literal.UriLiteral) {
            Literal.UriLiteral<QName> luri = (Literal.UriLiteral<QName>) pv;
            String shape = graphvizShapeForSo.get(luri.getValue());
            if (shape != null) {
              styleMap.put("shape", shape);
            }
          }
        }
      }
    }
  };

  /**
   * A map defining the mapping between SO terms and respective icons to be displayed when a DocumentRoot is exported.
   */
  public static final Map<URI, String> graphvizShapeForSo;

  static {
    graphvizShapeForSo = new HashMap<>();

    graphvizShapeForSo.put(URI.create("http://purl.obolibrary.org/obo/SO_0000139"), "ribosite");
    graphvizShapeForSo.put(URI.create("http://purl.obolibrary.org/obo/SO_0000316"), "cds");
  }
}


package com.thetransactioncompany.cors;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Properties;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Cross-Origin Resource Sharing (CORS) servlet filter.
 *
 *
The filter intercepts incoming HTTP requests and applies the CORS
 * policy as specified by the filter init parameters. The actual CORS
 * request is processed by the {@link CORSRequestHandler} class.
 *
 *
Supported filter init parameters:
 *
 *

 *
cors.allowGenericHttpRequests {true|false} defaults to {@code true}.
 *
cors.allowOrigin {"*"|origin-list} defaults to {@code *}.
 *
cors.allowSubdomains {true|false} defaults to {@code false}.
 *
cors.supportedMethods {method-list} defaults to {@code "GET, POST, HEAD, OPTIONS"}.
 *
cors.supportedHeaders {header-list} defaults to empty list.
 *
cors.exposedHeaders {header-list} defaults to empty list.
 *
cors.supportsCredentials {true|false} defaults to {@code true}.
 *
cors.maxAge {int} defaults to {@code -1} (unspecified).
 *

 *
 * @author Vladimir Dzhuvinov
 * @version $version$ (2011-12-02)
 */
public class CORSFilter
	implements Filter {

	/**
	 * The CORS filer configuration.
	 */
	private CORSConfiguration config;

	/**
	 * Encapsulates the CORS request handling logic.
	 */
	private CORSRequestHandler handler;

	/**
	 * Converts the initial filter parameters (typically specified in the
	 * {@code web.xml} file) to a Java properties hashtable. The parameter
	 * names become property keys.
	 *
	 * @param config The filter configuration.
	 *
	 * @return The context parameters as Java properties.
	 */
	private static Properties getFilterInitParameters(final FilterConfig config) {

		Properties props = new Properties();

		Enumeration en = config.getInitParameterNames();

		while (en.hasMoreElements()) {

			String key = (String)en.nextElement();
			String value = config.getInitParameter(key);

			props.setProperty(key, value);
		}

		return props;
	}

	/**
	 * This method is invoked by the web container to initialise the
	 * filter at startup.
	 *
	 * @param filterConfig The filter configuration.
	 *
	 * @throws ServletException On a filter initialisation exception.
	 */
	public void init(final FilterConfig filterConfig)
		throws ServletException {

		// Get the init params
		Properties props = getFilterInitParameters(filterConfig);

		// Extract and parse all required CORS filter properties
		try {
			config = new CORSConfiguration(props);

		} catch (CORSConfigurationException e) {

			throw new ServletException(e);
		}

		handler = new CORSRequestHandler(config);
	}

	/**
	 * Produces a simple HTTP text/plain response with the specified status
	 * code and message.
	 *
	 *
Note: The CORS filter avoids falling back to the default web
	 * container error page (typically a richly-formatted HTML page) to make
	 * it easier for XHR debugger tools to identify the cause of failed
	 * requests.
	 *
	 * @param sc      The HTTP status code.
	 * @param message The message.
	 *
	 * @throws IOException      On a I/O exception.
	 * @throws ServletException On a general request processing exception.
	 */
	private void printMessage(final HttpServletResponse response, final int sc, final String msg)
		throws IOException, ServletException {

		// Set the status code
		response.setStatus(sc);

		// Write the error message

		response.resetBuffer();

		response.setContentType("text/plain");

		PrintWriter out = response.getWriter();

		out.println("Cross-Origin Resource Sharing (CORS) Filter: " + msg);
	}

	/**
	 * Filters an HTTP request/reponse pair according to the configured CORS
	 * policy. Also tags the request with CORS information to downstream
	 * handlers.
	 *
	 * @param request  The servlet request.
	 * @param response The servlet response.
	 * @param chain    The filter chain.
	 *
	 * @throws IOException      On a I/O exception.
	 * @throws ServletException On a general request processing exception.
	 */
	private void doFilter(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain)
		throws IOException, ServletException {

		// Tag
		handler.tagRequest(request);

		CORSRequestType type = CORSRequestType.detect(request);

		try {
			if (type == CORSRequestType.ACTUAL) {
				// Simple/actual CORS request
				handler.handleActualRequest(request, response);
				chain.doFilter(request, response);
			}
			else if (type == CORSRequestType.PREFLIGHT) {
				// Preflight CORS request, handle but don't pass
				// further down the chain
				handler.handlePreflightRequest(request, response);
			}
			else if (config.allowGenericHttpRequests) {
				// Not a CORS request, but allow it through
				request.setAttribute("cors.isCorsRequest", false); // tag
				chain.doFilter(request, response);
			}
			else {
				// Generic HTTP requests denied
				request.setAttribute("cors.isCorsRequest", false); // tag
				printMessage(response, HttpServletResponse.SC_FORBIDDEN, "Generic HTTP requests not allowed");
			}

		} catch (InvalidCORSRequestException e) {

			request.setAttribute("cors.isCorsRequest", false); // tag
			printMessage(response, HttpServletResponse.SC_BAD_REQUEST, e.getMessage());

		} catch (CORSOriginDeniedException e) {

			String msg = e.getMessage() + ": " + e.getRequestOrigin();
			printMessage(response, HttpServletResponse.SC_FORBIDDEN, msg);

		} catch (UnsupportedHTTPMethodException e) {

			String msg = e.getMessage();

			HTTPMethod method = e.getRequestedMethod();

			if (method != null)
				msg = msg + ": " + method.toString();

			printMessage(response, HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);

		} catch (UnsupportedHTTPHeaderException e) {

			String msg = e.getMessage();

			HeaderFieldName header = e.getRequestHeader();

			if (header != null)
				msg = msg + ": " + header.toString();

			printMessage(response, HttpServletResponse.SC_FORBIDDEN, msg);
		}
	}

	/**
	 * Called by the servlet container each time a request/response pair is
	 * passed through the chain due to a client request for a resource at
	 * the end of the chain.
	 *
	 * @param request  The servlet request.
	 * @param response The servlet response.
	 * @param chain    The filter chain.
	 *
	 * @throws IOException      On a I/O exception.
	 * @throws ServletException On a general request processing exception.
	 */
	public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
		throws IOException, ServletException {

		if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {

			// Cast to HTTP
			doFilter((HttpServletRequest)request, (HttpServletResponse)response, chain);
		}
		else {
			throw new ServletException("Cannot filter non-HTTP requests/responses");
		}
	}

	/**
	 * Called by the web container to indicate to a filter that it is being
	 * taken out of service.
	 */
	public void destroy() {

		// do nothing
	}
}


package com.azaptree.services.domain.entity.impl;

/*
 * #%L
 * AZAPTREE-DOMAIN-ENTITY
 * %%
 * Copyright (C) 2012 - 2013 AZAPTREE.COM
 * %%
 * 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.
 * #L%
 */

import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.UUID;

import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.azaptree.services.domain.entity.VersionedEntity;
import com.azaptree.services.json.JsonUtils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.google.common.base.Optional;

public class DomainVersionedEntity extends DomainEntity implements VersionedEntity {

	protected long entityCreatedOn, entityUpdatedOn;

	protected volatile long entityVersion;

	protected UUID createdByEntityId, updatedByEntityId;

	public DomainVersionedEntity() {
	}

	public DomainVersionedEntity(final VersionedEntity entity) {
		super(entity);
		this.setEntityCreatedOn(entity.getEntityCreatedOn());
		if (entity.getCreatedByEntityId().isPresent()) {
			this.setCreatedBy(entity.getCreatedByEntityId().get());
		} else {
			this.setCreatedBy(null);
		}
		this.setEntityUpdatedOn(entity.getEntityUpdatedOn());
		if (entity.getUpdatedByEntityId().isPresent()) {
			this.setUpdatedBy(entity.getUpdatedByEntityId().get());
		} else {
			this.setUpdatedBy(null);
		}
		this.setEntityVersion(entity.getEntityVersion());
	}

	public DomainVersionedEntity(final InputStream json) throws IOException {
		super(json);
	}

	public DomainVersionedEntity(final String json) {
		super(json);
	}

	/**
	 * Call this method when the entity is updated to increment its version and update its lastupdatedByEntityId
	 *
	 * @param lastupdatedByEntityId
	 */
	public void created(final UUID createdByEntityId) {
		if (this.entityId != null) {
			throw new IllegalStateException("This entity has already been created: entityId = " + entityId);
		}
		this.entityId = UUID.randomUUID();
		this.entityVersion = 1;
		this.createdByEntityId = createdByEntityId;
		this.updatedByEntityId = createdByEntityId;
		this.entityCreatedOn = System.currentTimeMillis();
		this.entityUpdatedOn = this.entityCreatedOn;
	}

	/**
	 * Call this method when the entity is updated to increment its version and update its lastupdatedByEntityId
	 *
	 * @param lastupdatedByEntityId
	 */
	public void created() {
		if (this.entityId != null) {
			throw new IllegalStateException("This entity has already been created: entityId = " + entityId);
		}
		this.entityId = UUID.randomUUID();
		entityVersion = 1;
		this.entityCreatedOn = System.currentTimeMillis();
		this.entityUpdatedOn = this.entityCreatedOn;
	}

	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (!super.equals(obj)) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		final DomainVersionedEntity other = (DomainVersionedEntity) obj;
		return Objects.equals(createdByEntityId, other.createdByEntityId) &&
		        Objects.equals(entityCreatedOn, other.entityCreatedOn) &&
		        Objects.equals(entityUpdatedOn, other.entityUpdatedOn) &&
		        Objects.equals(entityVersion, other.entityVersion) &&
		        Objects.equals(updatedByEntityId, other.updatedByEntityId);
	}

	@Override
	public Optional<UUID> getCreatedByEntityId() {
		if (createdByEntityId == null) {
			return Optional.absent();
		}
		return Optional.of(createdByEntityId);
	}

	@Override
	public long getEntityCreatedOn() {
		return entityCreatedOn;
	}

	@Override
	public long getEntityUpdatedOn() {
		return entityUpdatedOn;
	}

	@Override
	public long getEntityVersion() {
		return entityVersion;
	}

	@Override
	public Optional<UUID> getUpdatedByEntityId() {
		if (updatedByEntityId == null) {
			return Optional.absent();
		}
		return Optional.of(updatedByEntityId);
	}

	@Override
	public int hashCode() {
		return java.util.Objects.hash(entityId, entityVersion);
	}

	public void setCreatedBy(final UUID createdByEntityId) {
		this.createdByEntityId = createdByEntityId;
	}

	/**
	 * Knows how to parse the following JSON fields:
	 *
	 *

	 *
entityId

	 *
entityVersion

	 *
entityCreatedOn

	 *
createdByEntityId

	 *
entityUpdatedOn

	 *
updatedByEntityId

	 *

	 *
	 * For any other field, JSON parsing is delegated to init(JsonParser parser)
	 *
	 */
	@SuppressWarnings("incomplete-switch")
	@Override
	public void init(InputStream json) throws IOException {
		try (final JsonParser parser = JsonUtils.createJsonParser(json)) {
			JsonToken tk;
			while ((tk = parser.nextToken()) != null) {
				switch (tk) {
				case FIELD_NAME:
					final String fieldName = parser.getCurrentName();
					if (fieldName.equals("entityId")) {
						setEntityId(UUID.fromString(parser.nextTextValue()));
					} else if (fieldName.equals("entityVersion")) {
						setEntityVersion(parser.nextLongValue(0));
					} else if (fieldName.equals("entityCreatedOn")) {
						setEntityCreatedOn(parser.nextLongValue(0));
					} else if (fieldName.equals("createdByEntityId")) {
						setCreatedBy(UUID.fromString(parser.nextTextValue()));
					} else if (fieldName.equals("entityUpdatedOn")) {
						setEntityUpdatedOn(parser.nextLongValue(0));
					} else if (fieldName.equals("updatedByEntityId")) {
						setUpdatedBy(UUID.fromString(parser.nextTextValue()));
					} else {
						init(parser);
					}
					break;
				}
			}
		}

	}

	/**
	 * Sub-classes should override this to parse sub-class specific fields.
	 *
	 * This is invoked by init(InputStream), when an unknown field is encountered
	 *
	 * @param parser
	 */
	protected void init(JsonParser parser) throws IOException {
		LoggerFactory.getLogger(getClass()).warn("init(JsonParser parser) invoked to handle field: {}", parser.getCurrentName());
	}

	public void setEntityCreatedOn(final long entityCreatedOn) {
		this.entityCreatedOn = entityCreatedOn;
	}

	public void setEntityUpdatedOn(final long entityLastupdatedOn) {
		entityUpdatedOn = entityLastupdatedOn;
	}

	public void setEntityVersion(final long entityVersion) {
		this.entityVersion = entityVersion;
	}

	public void setUpdatedBy(final UUID lastUpdatedByEntityId) {
		updatedByEntityId = lastUpdatedByEntityId;
	}

	/**
	 * Call this method when the entity is updated before it is persisted to increment its version and update its lastupdatedByEntityId
	 *
	 * @param lastupdatedByEntityId
	 *            REQUIRED
	 */
	public void updated(final UUID lastupdatedByEntityId) {
		if (this.entityId == null) {
			throw new IllegalStateException("The entity has not yet been created : entityId == null");
		}
		Assert.notNull(lastupdatedByEntityId, "lastupdatedByEntityId is required");
		entityVersion++;
		updatedByEntityId = lastupdatedByEntityId;
		entityUpdatedOn = System.currentTimeMillis();
	}

	/**
	 * Call this method when the entity is updated before it is persisted to increment its version and update its lastupdatedByEntityId
	 *
	 * @param lastupdatedByEntityId
	 */
	public void updated() {
		if (this.entityId == null) {
			throw new IllegalStateException("The entity has not yet been created : entityId == null");
		}
		entityVersion++;
		entityUpdatedOn = System.currentTimeMillis();
	}

}


package hudson.plugins.dry.parser.cpd;

import hudson.plugins.analysis.util.PackageDetectors;
import hudson.plugins.dry.parser.AbstractDryParser;
import hudson.plugins.dry.parser.DuplicateCode;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.digester3.Digester;
import org.xml.sax.SAXException;

/**
 * A parser for PMD's CPD XML files.
 *
 * @author Ulli Hafner
 */
public class CpdParser extends AbstractDryParser {
    /** Unique ID of this class. */
    private static final long serialVersionUID = 6507147028628714706L;

    /**
     * Creates a new instance of {@link CpdParser}.
     *
     * @param highThreshold
     *            minimum number of duplicate lines for high priority warnings
     * @param normalThreshold
     *            minimum number of duplicate lines for normal priority warnings
     */
    public CpdParser(final int highThreshold, final int normalThreshold) {
        super(highThreshold, normalThreshold);
    }

    @Override
    public boolean accepts(final InputStream file) {
        try {
            Digester digester = new Digester();
            digester.setValidating(false);
            digester.setClassLoader(CpdParser.class.getClassLoader());

            String duplicationXPath = "*/pmd-cpd";
            digester.addObjectCreate(duplicationXPath, String.class);

            Object result = digester.parse(file);
            if (result instanceof String) {
                return true;
            }

        }
        catch (IOException exception) {
            // ignore and return false
        }
        catch (SAXException exception) {
            // ignore and return false
        }
        return false;
    }

    @Override
    public Collection<DuplicateCode> parse(final InputStream file, final String moduleName) throws InvocationTargetException {
        try {
            Digester digester = new Digester();
            digester.setValidating(false);
            digester.setClassLoader(CpdParser.class.getClassLoader());

            ArrayList<Duplication> duplications = new ArrayList<Duplication>();
            digester.push(duplications);

            String duplicationXPath = "*/pmd-cpd/duplication";
            digester.addObjectCreate(duplicationXPath, Duplication.class);
            digester.addSetProperties(duplicationXPath);
            digester.addCallMethod(duplicationXPath + "/codefragment", "setCodeFragment", 0);
            digester.addSetNext(duplicationXPath, "add");

            String fileXPath = duplicationXPath + "/file";
            digester.addObjectCreate(fileXPath, SourceFile.class);
            digester.addSetProperties(fileXPath);
            digester.addSetNext(fileXPath, "addFile", SourceFile.class.getName());

            Object result = digester.parse(file);
            if (result != duplications) { // NOPMD
                throw new SAXException("Input stream is not a valid CPD file.");
            }

            return convert(duplications, moduleName);
        }
        catch (IOException exception) {
            throw new InvocationTargetException(exception);
        }
        catch (SAXException exception) {
            throw new InvocationTargetException(exception);
        }
    }

    /**
     * Converts the internal structure to the annotations API.
     *
     * @param duplications
     *            the internal maven module
     * @param moduleName
     *            name of the maven module
     * @return a maven module of the annotations API
     */
    private Collection<DuplicateCode> convert(final List<Duplication> duplications, final String moduleName) {
        List<DuplicateCode> annotations = new ArrayList<DuplicateCode>();

        for (Duplication duplication : duplications) {
            List<DuplicateCode> codeBlocks = new ArrayList<DuplicateCode>();
            boolean isDerived = false;
            for (SourceFile file : duplication.getFiles()) {
                // TODO: check why PMD reports a length + 1
                DuplicateCode annotation = new DuplicateCode(getPriority(duplication.getLines()), file.getLine(), duplication.getLines(), file.getPath(), isDerived);
                annotation.setSourceCode(duplication.getCodeFragment());
                annotation.setModuleName(moduleName);
                codeBlocks.add(annotation);
                isDerived = true;
            }
            for (DuplicateCode block : codeBlocks) {
                block.linkTo(codeBlocks);

                block.setPackageName(PackageDetectors.detectPackageName(block.getFileName()));
            }
            annotations.addAll(codeBlocks);
        }
        return annotations;
    }
}


/*******************************************************************************
 *
 * Copyright (C) 2015 Mytech Ingenieria Aplicada <http://www.mytechia.com>
 * Copyright (C) 2015 Alejandro Paz <alejandropl@lagostelle.com>
 *
 * This file is part of Vineyard.
 *
 * Vineyard is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * Vineyard is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Vineyard. If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

package com.hi3project.vineyard.container.yotta;

import com.hi3project.vineyard.container.AbstractBSDMServiceContainer;
import com.hi3project.broccoli.bsdl.api.ISemanticIdentifier;
import com.hi3project.broccoli.bsdl.api.ISemanticLocator;
import com.hi3project.broccoli.bsdm.api.asyncronous.IAsyncMessageClient;
import com.hi3project.broccoli.bsdm.api.asyncronous.IChannelConsumer;
import com.hi3project.broccoli.bsdm.api.asyncronous.IChannelProducer;
import com.hi3project.broccoli.bsdm.api.asyncronous.IMessage;
import com.hi3project.broccoli.bsdm.api.asyncronous.IMessageBroker;
import com.hi3project.broccoli.bsdm.api.asyncronous.IMessageTimeoutCallback;
import com.hi3project.broccoli.bsdf.api.deployment.container.IBSDMServiceContainer;
import com.hi3project.broccoli.bsdf.api.discovery.IFunctionalitySearchResult;
import com.hi3project.broccoli.bsdf.api.discovery.IMatchmaker;
import com.hi3project.broccoli.bsdf.api.discovery.IServiceRegistry;
import com.hi3project.broccoli.bsdm.api.profile.functionality.IRequestedFunctionality;
import com.hi3project.broccoli.bsdm.impl.asyncronous.DescriptorData;
import com.hi3project.broccoli.bsdf.impl.asyncronous.RegisterServiceRequestMessage;
import com.hi3project.broccoli.bsdf.impl.asyncronous.SearchFunctionalityRequestMessage;
import com.hi3project.broccoli.bsdf.impl.asyncronous.SearchFunctionalityResultMessage;
import com.hi3project.vineyard.tools.Deployer;
import com.hi3project.vineyard.tools.Unpacker;
import com.hi3project.broccoli.bsdf.impl.deployment.bd.LoadedServiceVO;
import com.hi3project.vineyard.registry.client.ClientRequester;
import com.hi3project.vineyard.comm.broker.AsyncMessageBroker;
import com.hi3project.broccoli.bsdf.impl.parsing.ServiceDescriptionLoader;
import com.hi3project.broccoli.bsdf.impl.serializing.JSONMessageSerializer;
import com.hi3project.vineyard.registry.server.BSDMServiceRegistry;
import com.hi3project.vineyard.registry.server.SimpleStructuralMatchmaker;
import com.hi3project.broccoli.bsdf.exceptions.MessageBrokerException;
import com.hi3project.broccoli.bsdl.api.parsing.PreParsingRule;
import com.hi3project.broccoli.bsdl.impl.exceptions.ModelException;
import com.hi3project.broccoli.bsdm.impl.exceptions.ServiceExecutionException;
import com.hi3project.broccoli.bsdm.impl.exceptions.ServiceGroundingException;
import com.hi3project.broccoli.io.BSDFLogger;
import com.hi3project.broccoli.io.DescriptorReader;
import com.hi3project.vineyard.comm.ChannelFactory;
import com.hi3project.vineyard.comm.FunctionalityGroundingFactory;
import com.hi3project.vineyard.comm.ReceivedMessagesChecker;
import com.hi3project.vineyard.comm.ServiceGroundingFactory;
import com.hi3project.vineyard.registry.client.BrokerConnectorsConfig;
import java.util.ArrayList;
import java.util.Collection;

/**
 *

 * Description:

 * Implementation of IBSDMServiceContainer.
 *
 *
 *

 * Creation date:
 * 17-07-2014

 *
 *

 * Changelog:
 *

 *
 1 , 17-07-2014 - Initial release

 *

 *
 *
 *
 * @version 1
 */
public final class BSDMServiceContainer extends AbstractBSDMServiceContainer implements IBSDMServiceContainer
{

    private BSDMServiceRegistry bsdmServiceRegistry;

    private AsyncMessageBroker messageBroker;

    private Collection<ConnectionWithExternalContainer> externalContainers;

    private IChannelProducer containerChannelProducer = null;

    private MessageReceiverWithTimeout messageReceiverWithTimeoutForSearchResults;

    private String urlContainer;

    private String ipContainer;

    private static final String CONV_ID_SEPARATOR = ";";

    public BSDMServiceContainer(
            ISemanticLocator workingLocation,
            ISemanticIdentifier containerName) throws ModelException
    {
        this(workingLocation, containerName, BrokerConnectorsConfig.openWireConnectorURL);
    }

    public BSDMServiceContainer(
            ISemanticLocator workingLocation,
            ISemanticIdentifier containerName,
            String urlContainer) throws ModelException
    {
        super(workingLocation, containerName);

        this.urlContainer = urlContainer;

        this.ipContainer = AbstractBSDMServiceContainer.getIPfromURL(urlContainer);

        this.messageReceiverWithTimeoutForSearchResults = new MessageReceiverWithTimeout("Receiver for " + containerName.getLastName());

        this.bsdmServiceRegistry = new BSDMServiceRegistry(
                ServiceGroundingFactory.getSingleton(),
                FunctionalityGroundingFactory.getSingleton(),
                new JSONMessageSerializer(ServiceGroundingFactory.getSingleton(), FunctionalityGroundingFactory.getSingleton()));
        this.bsdmServiceRegistry.setMatchmaker(new SimpleStructuralMatchmaker(bsdlRegistry));
        this.messageBroker
                = new AsyncMessageBroker("AsyncMessageBroker-" + containerName.getLastName());
        this.externalContainers = new ArrayList<ConnectionWithExternalContainer>();

        BSDFLogger.getLogger().info("Instances a BSDMServiceContainer");
    }

    @Override
    public synchronized void start() throws ServiceExecutionException
    {
        try
        {

            this.messageBroker.setMainControlChannel(this);

            this.messageReceiverWithTimeoutForSearchResults.start();

            this.messageBroker.start();

            this.bsdmServiceRegistry.initServiceImplementations();

        } catch (MessageBrokerException ex)
        {
            throw new ServiceExecutionException(ex.getMessage(), ex);
        }
    }

    @Override
    public synchronized void stop() throws ServiceExecutionException
    {
        try
        {

            if (null != this.containerChannelProducer)
            {
                this.containerChannelProducer.close();
                this.containerChannelProducer = null;
            }

            this.messageBroker.stop();

            this.messageReceiverWithTimeoutForSearchResults.stop();

        } catch (MessageBrokerException ex)
        {
            throw new ServiceExecutionException(ex.getMessage(), ex);
        }
    }

    @Override
    public synchronized void restart() throws ServiceExecutionException
    {
        try
        {

            this.messageBroker.restart();

        } catch (MessageBrokerException ex)
        {
            throw new ServiceExecutionException(ex.getMessage(), ex);
        }
    }

    /*
     With the current implementation, a service must be registered before the
     message broker is started... or restart the broker to activate messaging for
     that service.
     */
    @Override
    public void registerService(ISemanticLocator packedServiceDescriptor) throws ServiceExecutionException
    {
        try
        {

            BSDFLogger.getLogger().info("Deploys service(s) from: " + packedServiceDescriptor.toString());

            Collection<ISemanticIdentifier> deployedServices = this.deploy(packedServiceDescriptor, bsdmServiceRegistry);

            for (ISemanticIdentifier deployedService : deployedServices)
            {
                this.messageBroker.registerService(
                        this.bsdmServiceRegistry.getService(deployedService).applyConnectorURL(this.urlContainer));
            }

        } catch (ModelException ex)
        {
            BSDFLogger.getLogger().debug("Cannot deploy service(s) from: " + packedServiceDescriptor.toString()
                    + " . Exception: " + ex.toString());
            throw new ServiceExecutionException(ex.getMessage(), ex);
        }
    }

    @Override
    public IMessageBroker getMessageBroker()
    {
        return this.messageBroker;
    }

    @Override
    public IServiceRegistry getBSDMServiceRegistry()
    {
        return this.bsdmServiceRegistry;
    }

    @Override
    public IMatchmaker getMatchmaker()
    {
        return this.bsdmServiceRegistry.getMatchmaker();
    }

    @Override
    public void setMatchmaker(IMatchmaker matchmaker)
    {
        this.bsdmServiceRegistry.setMatchmaker(matchmaker);
    }

    @Override
    public String toString()
    {
        return "BSDMServiceContainer{" + "workingLocation=" + workingLocation.getLastName() + '}';
    }

    @Override
    public synchronized void activateControlChannels() throws ModelException
    {

        ControlChannelReceiver receiver = new ControlChannelReceiver();
        ReceivedMessagesChecker messagesChecker = new ReceivedMessagesChecker();

        IChannelConsumer containerChannelConsumer
                = ChannelFactory.getSingleton().controlChannelConsumerInstanceFor(
                        BrokerConnectorsConfig.getOpenWireURLfromIP(this.ipContainer),
                        ClientRequester.ContainerRequestChannelName,
                        this.bsdlRegistry,
                        messagesChecker);

        containerChannelConsumer.addClientCallback(receiver);

        containerChannelConsumer
                = ChannelFactory.getSingleton().controlChannelConsumerInstanceFor(
                        BrokerConnectorsConfig.getStompURLfromIP(this.ipContainer),
                        ClientRequester.ContainerRequestChannelName,
                        this.bsdlRegistry,
                        messagesChecker);

        containerChannelConsumer.addClientCallback(receiver);

        containerChannelConsumer
                = ChannelFactory.getSingleton().controlChannelConsumerInstanceFor(
                        BrokerConnectorsConfig.getWSURLfromIP(this.ipContainer),
                        ClientRequester.ContainerRequestChannelName,
                        this.bsdlRegistry,
                        messagesChecker);

        containerChannelConsumer.addClientCallback(receiver);

        containerChannelProducer
                = ChannelFactory.getSingleton().controlChannelProducerInstanceFor(
                        this.urlContainer,
                        ClientRequester.ContainerResponseChannelName,
                        this.bsdlRegistry);

    }

    @Override
    public synchronized void addRemoteContainer(ISemanticIdentifier remoteBrokerIdentifier) throws ServiceExecutionException
    {
        BSDFLogger.getLogger().info("Registers connection to remote container: " + remoteBrokerIdentifier.toString());
        ConnectionWithExternalContainer externalContainer
                = new ConnectionWithExternalContainer(remoteBrokerIdentifier, this.bsdlRegistry);
        try
        {
            externalContainer.connect();
            externalContainer.addResponseCallback(new IAsyncMessageClient()
            {

                @Override
                public void receiveMessage(IMessage msg) throws ModelException
                {
                    if (msg instanceof SearchFunctionalityResultMessage)
                    {
                        BSDFLogger.getLogger().info("Process received SearchFunctionalityResultMessage: " + msg.toString()
                                + " from: " + BSDMServiceContainer.this.toString());
                        BSDMServiceContainer.this.messageReceiverWithTimeoutForSearchResults.receiveMessage(msg);
                    }
                }

                @Override
                public String getName()
                {
                    return BSDMServiceContainer.this.containerName.getLastName();
                }
            });
        } catch (ModelException ex)
        {
            throw new ServiceExecutionException(remoteBrokerIdentifier.toString(), ex);
        }
        this.externalContainers.add(externalContainer);
    }

    private synchronized Collection<ISemanticIdentifier> deploy(
            ISemanticLocator packedServiceDescriptor,
            IServiceRegistry bsdmServiceRegistry) throws ModelException
    {
        SimpleDeployerForContainerWithServiceRegistry deployer
                = new SimpleDeployerForContainerWithServiceRegistry(
                        new Unpacker(),
                        this.servicesDB,
                        workingLocation,
                        bsdmServiceRegistry,
                        this.bsdlRegistry);

        deployer.addPreParsingRule(
                new PreParsingRule("with", "property", "url", "value", this.urlContainer));

        return deployer.deployService(packedServiceDescriptor);
    }

    private SearchFunctionalityResultMessage searchForFunctionalities(
            SearchFunctionalityRequestMessage sfRequestMsg,
            Collection<IRequestedFunctionality> readFunctionalities) throws ServiceGroundingException, ModelException
    {
        SearchFunctionalityResultMessage sfResultMsg
                = new SearchFunctionalityResultMessage(
                        sfRequestMsg.getClientName(),
                        sfRequestMsg.getConversationId());

        for (IRequestedFunctionality reqFunc : readFunctionalities)
        {
            Collection<IFunctionalitySearchResult> searchResults = getBSDMServiceRegistry().searchFor(reqFunc);
            for (IFunctionalitySearchResult searchResult : searchResults)
            {
                sfResultMsg.addSearchResult(searchResult);
                Collection<LoadedServiceVO> serviceVOs = servicesDB.getServiceVObyServiceIdentifier(searchResult.getServiceDescription().getIdentifier());
                for (LoadedServiceVO serviceVO : serviceVOs)
                {

                    String serviceContents = new DescriptorReader(serviceVO.getServiceLocators().getServiceDescriptorLocator()).readAsString();
                    sfResultMsg.addServiceDescriptorContents(
                            new DescriptorData(
                                    serviceVO.getServiceLocators().getServiceDescriptorLocator().getLastName(),
                                    serviceContents));

                    for (ISemanticLocator ontologieDescriptorLocator : serviceVO.getServiceLocators().getOntologiesDescriptorLocators())
                    {
                        String ontologyContents = new DescriptorReader(ontologieDescriptorLocator).readAsString();
                        sfResultMsg.addOntologyDescriptorContents(
                                new DescriptorData(
                                        ontologieDescriptorLocator.getLastName(),
                                        ontologyContents));
                    }

                }

            }
        }

        return sfResultMsg;
    }

    private void sendSearchResultToExternalContainers(
            SearchFunctionalityRequestMessage sfRequestMsg,
            String clientName) throws ServiceGroundingException
    {
        for (ConnectionWithExternalContainer externalContainer : BSDMServiceContainer.this.externalContainers)
        {
            final SearchFunctionalityRequestMessage redirectMsg;
            try
            {
                redirectMsg = (SearchFunctionalityRequestMessage) sfRequestMsg.clone();
                redirectMsg.setClientName(clientName);
                redirectMsg.setConversationId(sfRequestMsg.getClientName() + CONV_ID_SEPARATOR + sfRequestMsg.getConversationId());
                externalContainer.getRequestChannelProducer().send(redirectMsg);
            } catch (CloneNotSupportedException ex)
            {
                throw new ServiceGroundingException("Cannot redirect search functionality message to external container", ex);
            }
        }
    }

    private class ControlChannelReceiver implements IAsyncMessageClient
    {

        @Override
        public void receiveMessage(IMessage msg) throws ModelException
        {
            if (msg instanceof SearchFunctionalityRequestMessage)
            {
                BSDFLogger.getLogger().info("Process received SearchFunctionalityRequestMessage: " + msg.toString()
                        + " from: " + this.toString());

                final SearchFunctionalityRequestMessage sfRequestMsg = (SearchFunctionalityRequestMessage) msg;

                // load the functionalities as IRequestedFunctionality instances
                ServiceDescriptionLoader loader
                        = new ServiceDescriptionLoader(
                                ServiceGroundingFactory.getSingleton(),
                                FunctionalityGroundingFactory.getSingleton(),
                                bsdlRegistry,
                                new JSONMessageSerializer(ServiceGroundingFactory.getSingleton(), FunctionalityGroundingFactory.getSingleton()));
                Collection<IRequestedFunctionality> readFunctionalities = loader.readFunctionalities(sfRequestMsg.getRequestedFunctionalityContents());

                // search functionalitites and build the result message
                final SearchFunctionalityResultMessage sfResultMsg = searchForFunctionalities(sfRequestMsg, readFunctionalities);

                if (BSDMServiceContainer.this.externalContainers.size() > 0)
                {
                    // if there are any external containers, a timeout callback is created
                    //to handle the SearchFunctionalityResultMessage received from them
                    TimeoutCallback callback = new TimeoutCallback(5000, new IMessageTimeoutCallback()
                    {

                        @Override
                        public void timeout(Collection<IMessage> messages)
                        {
                            for (IMessage msg : messages)
                            {
                                if (msg instanceof SearchFunctionalityResultMessage)
                                {
                                    // for each SearchFunctionalityResultMessage received, its contents
                                    //are merged with the results obtained for This container, so only
                                    //one results message is sent to the client
                                    SearchFunctionalityResultMessage sfrMessage = (SearchFunctionalityResultMessage) msg;
                                    if (sfrMessage.getClientName().equals(BSDMServiceContainer.this.containerName.getLastName()))
                                    {
                                        String[] split = sfrMessage.getConversationId().split(CONV_ID_SEPARATOR);
                                        if (split.length != 2)
                                        {
                                            BSDFLogger.getLogger().error(
                                                    "ConversationId should be: [clientName;clientConvId] but is: ["
                                                    + sfrMessage.getConversationId()
                                                    + "]");
                                        }
                                        try
                                        {
                                            SearchFunctionalityResultMessage redirectMsg = (SearchFunctionalityResultMessage) sfrMessage.clone();
                                            redirectMsg.setClientName(split[0]);
                                            redirectMsg.setConversationId(split[1]);

                                            sfResultMsg.merge(redirectMsg);

                                        } catch (CloneNotSupportedException ex)
                                        {
                                            BSDFLogger.getLogger().error("Error redirecting a SearchFunctionalityResultMessage", ex);
                                        }
                                    }

                                }
                            }
                            try
                            {
                                // send results back
                                BSDMServiceContainer.this.containerChannelProducer.send(sfResultMsg);
                            } catch (ServiceGroundingException ex)
                            {
                                BSDFLogger.getLogger().error(ex.toString());
                            }
                        }
                    });

                    // registers the timeout callback with the proper conversationId
                    BSDMServiceContainer.this.messageReceiverWithTimeoutForSearchResults.addCalback(
                            sfRequestMsg.getClientName() + CONV_ID_SEPARATOR + sfRequestMsg.getConversationId(),
                            callback);

                    // send search functionality msg to external containers
                    BSDMServiceContainer.this.sendSearchResultToExternalContainers(sfRequestMsg, this.getName());

                } else
                {
                    // send results back
                    BSDMServiceContainer.this.containerChannelProducer.send(sfResultMsg);
                }

            }

            if (msg instanceof RegisterServiceRequestMessage)
            {
                BSDFLogger.getLogger().info("Process received RegisterServiceRequestMessage: " + msg.toString()
                        + " from: " + this.toString());

                final RegisterServiceRequestMessage rsRequestMessage = (RegisterServiceRequestMessage) msg;

                // "deploy" the service(s) with the given descriptors data
                Deployer deployer = new Deployer(BSDMServiceContainer.this.getServicesDB(), BSDMServiceContainer.this.getWorkingLocation());
                deployer.deployService(rsRequestMessage, bsdlRegistry, bsdmServiceRegistry);

            }
        }

        @Override
        public String getName()
        {
            return BSDMServiceContainer.this.containerName.getLastName();
        }
    }

}


package com.azaptree.services.security.config.spring;

/*
 * #%L
 * AZAPTREE SECURITY SERVICE
 * %%
 * Copyright (C) 2012 - 2013 AZAPTREE.COM
 * %%
 * 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.
 * #L%
 */

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.Transactional;

import com.azaptree.services.security.CredentialNames;
import com.azaptree.services.security.CredentialToByteSourceConverter;
import com.azaptree.services.security.SecurityCredentialsService;
import com.azaptree.services.security.SecurityService;
import com.azaptree.services.security.SessionManagementService;
import com.azaptree.services.security.SubjectRepositoryService;
import com.azaptree.services.security.config.SecurityServiceConfiguration;
import com.azaptree.services.security.credentialToByteSourceConverters.StringToByteSourceConverter;
import com.azaptree.services.security.dao.HashServiceConfigurationDAO;
import com.azaptree.services.security.domain.config.HashServiceConfiguration;
import com.azaptree.services.security.domain.config.impl.HashServiceConfig;
import com.azaptree.services.security.impl.SecurityCredentialsServiceImpl;
import com.azaptree.services.security.impl.SecurityServiceImpl;
import com.azaptree.services.security.impl.SessionManagementServiceImpl;
import com.azaptree.services.security.impl.SubjectRepositoryServiceImpl;

@Configuration
public abstract class SecurityServiceSpringConfiguration implements SecurityServiceConfiguration {

	@Autowired
	private HashServiceConfigurationDAO hashServiceConfigurationDAO;

	protected Map<String, CredentialToByteSourceConverter<?>> credentialToByteSourceConverters() {
		final Map<String, CredentialToByteSourceConverter<?>> converters = new HashMap<>();
		converters.put(CredentialNames.PASSWORD.credentialName, stringToByteSourceConverter());
		converters.put(CredentialNames.FORGOT_PASSWORD_ANSWER_1.credentialName, stringToByteSourceConverter());
		return converters;
	}

	/**
	 *
	 * @return the name of the HashServiceConfiguration to load from the database
	 */
	protected abstract String getHashServiceConfigurationName();

	/**
	 * Will try to lookup the HashServiceConfiguration using the name specified by {@link #getHashServiceConfigurationName()}
	 *
	 * @return
	 */
	@Transactional
	protected HashServiceConfiguration hashServiceConfiguration() {
		Exception exception = null;
		for (int i = 0; i < 3; i++) {
			final HashServiceConfiguration config = hashServiceConfigurationDAO.findByName(getHashServiceConfigurationName());
			if (config != null) {
				return config;
			}

			try {
				return hashServiceConfigurationDAO.create(newHashServiceConfiguration());
			} catch (Exception e) {
				exception = e;
				try {
					Thread.sleep((long) (Math.random() * 1000));
				} catch (InterruptedException e2) {
					// ignore
				}
			}
		}

		throw new RuntimeException("hashServiceConfiguration() failed", exception);
	}

	/**
	 * Simply returns a new HashServiceConfig instance :
	 *
	 * <code>
	 * return new HashServiceConfig(getHashServiceConfigurationName());
	 * </code>
	 *
	 * Override this method if the application requires a different configuration
	 *
	 * @return
	 */
	protected HashServiceConfiguration newHashServiceConfiguration() {
		return new HashServiceConfig(getHashServiceConfigurationName());
	}

	@Override
	@Bean
	public SecurityCredentialsService securityCredentialsService() {
		return new SecurityCredentialsServiceImpl(credentialToByteSourceConverters());
	}

	@Override
	@Bean
	public SecurityService securityService() {
		return new SecurityServiceImpl(hashServiceConfiguration());
	}

	@Override
	@Bean
	public SessionManagementService sessionManagementService() {
		return new SessionManagementServiceImpl();
	}

	@Bean
	public StringToByteSourceConverter stringToByteSourceConverter() {
		return new StringToByteSourceConverter();
	}

	@Override
	@Bean
	public SubjectRepositoryService subjectRepositoryService() {
		return new SubjectRepositoryServiceImpl();
	}

}


/*******************************************************************************
 *
 *   Copyright (C) 2005 Sean Russell
 *
 *   This file is part of Broccoli.
 *
 *   Broccoli is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Broccoli is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with Broccoli.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

package com.hi3project.vineyard.comm.stomp.gozirraws;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * Implements a Stomp server.  This is a tiny embeddable server that
 * can be used as an inter-net or intra-VM server to handle Stomp
 * requests.
 *
 * For intra-VM requests, use getClient() to get an instance of a Stomp
 * client.
 *
 * Example usage:
 *

 *   Server s = new Server( 61656 );  // To start it
 *   s.listen( 12345 );               // To listen on another port
 *   // Note that 's' is now listening on TWO ports
 *   s.close( 61656 );                // To close a port
 *   s.close( 12345 );                // Now no ports are open.
 *   // This is effectively the same as:
 *   i = new Server();                // A server with no network (intra-VM)
 *   Stomp c = s.getClient();         // Creates and returns a client
 *   // that is connected to the server directly via VM method calls --
 *   // there is no network communication between this client and the
 *   // server.
 *   s.stop();                        // To stop the server
 *   i.stop();
 *

 *
 * FIXME
 * Queues are not implemented.  Therefore, this server operates as an IRC,
 * rather than a Jabber, messaging system.  That is, all messages arriving
 * before a subscription request are lost to that client.  When Queues are
 * implemented, there will be an option to set persistence on the messages.
 *
 * Would it be good if -- given a session ID -- clients could
 * reconnect and complete transactions?
 *
 * (c)2005 Sean Russell
 */
public class Server {
  private Queue _message_queue;
  private Map _transactions;
  private Map _listeners;
  private ConnectionListener _connection_listener;
  private Authenticator _authenticator = new AllowAllAuthenticator();

  /**
   * Instantiates an intra-VM server.  This will open no ports, and
   * can not be connected to except by intra-VM threads.  A port can
   * be opened on this server by using the listen() method.
   */
  public Server() {
    _message_queue = new FileQueue();
    _transactions = new HashMap();
    _listeners = new HashMap();
  }

  /**
   * Instantiates an inter-network server listening on the supplied
   * port.  Additional ports can be listened on by using the listen()
   * method.
   *
   * @param port This port will be opened and will listen for client
   *  connections.  If the port value is less than 0, the default port
   *  of 61626 will be used.
   */
  public Server( int port ) throws IOException {
    this( port, null );
  }

  /**
   * Instantiates an inter-network server listening on the supplied
   * port.  Additional ports can be listened on by using the listen()
   * method.
   *
   * @param port This port will be opened and will listen for client
   *  connections.  If the port value is less than 0, the default port
   *  of 61626 will be used.
   * @param auth A class responsible for authenticating connections.
   */
  public Server( int port, Authenticator auth ) throws IOException {
    this();
    if (port < 0) port = 61626;
    if (auth != null) _authenticator = auth;
    listen(port);
  }

  /**
   * Opens a port for internet connections.  A single server can listen
   * on multiple ports, so calling this method multiple times will open
   * multiple ports.
   *
   * @param port This port will be opened and will listen for client
   *  connections.  If the port value is less than 0, an exception is
   *  thrown.
   */
  public void listen( int port ) throws IOException {
    _connection_listener = new ConnectionListener( port, this );
    _connection_listener.start();
  }

  /**
   * Called by a SocketHandler to notify the server that a client
   * has disconnected.  Is not, and should not, be called from anywhere
   * else.
   */
  protected void disconnect( SocketHandler s ) {
    _connection_listener.disconnect( s );
  }

  /**
   * This class is necessary because Java is RETARDED.  Specifically,
   * it lacks closures.
   *
   * Listenens on a port and accepts client connections.  For each
   * connection, spawns a SocketHandler for the connection.  When
   * shut down, stops receiving connections and shuts down all existing
   * client connections.
   */
  private class ConnectionListener extends Thread {
    private int _port;
    private Server _server;
    private ServerSocket _serve_sock;
    private List _handlers = new ArrayList();

    protected ConnectionListener( int port, Server server ) {
      _port = port;
      _server = server;
    }

    public void run() {
      Socket sock = null;
      try {
        _serve_sock = new ServerSocket( _port );
        while (!isInterrupted()) {
          sock = _serve_sock.accept();
          try {
            Thread handler = new SocketHandler( sock, _server );
            handler.start();
            _handlers.add( handler );
          } catch (IOException e) {
            e.printStackTrace( System.err );
          }
        }
      } catch (SocketException e) {
        // This gets thrown when the accept() is interrupted
      } catch (IOException e) {
        e.printStackTrace( System.err );
      } catch (Exception e) {
        e.printStackTrace( System.err );
      }
      for (Iterator i=_handlers.iterator(); i.hasNext(); ) {
        try {
          Thread t = (Thread)i.next();
          t.interrupt();
          Thread.yield();
        } catch (Exception e) { }
      }
    }

    /**
     * Shut down operations.
     */
    protected void shutdown() {
      this.interrupt();
      try { _serve_sock.close(); } catch (Exception e) {}
    }

    /**
     * Called by the server to notify this object that a SocketHandler
     * has disconnected itself.
     */
    protected void disconnect( SocketHandler h ) {
      _handlers.remove(h);
    }
  }

  /**
   * Shuts down the server, closing all connections.
   */
  public void stop() {
    // The _connection_listener will be null if this is not a network
    // socket server.
    if (_connection_listener != null) {
      _connection_listener.shutdown();
    }
    close( -1 );
    Thread.yield();
  }

  /**
   * Sets the queuing mechanism used for all further messages.  Any
   * existing undelivered messages will not use this queue.
   * FIXME Not implemented
   *
   * @param q
   */
  public void setQueue( Queue q ) {
    _message_queue = q;
  }

  /**
   * Closes a port.  All connections on this port will be closed.
   *
   * @param port The port to close.  A value of less than -1 closes all ports
   */
  public void close( int port ) {
    for (Iterator i = _listeners.keySet().iterator(); i.hasNext(); ) {
      Object k = i.next();
      Object s = _listeners.get(k);
      if (s instanceof SocketHandler) {
        SocketHandler sh = (SocketHandler)s;
        if (port == -1 || sh.isPort( port )) {
          sh.interrupt();
          sh.close();
          _transactions.remove( s );
          _listeners.remove( k );
        }
      }
    }
  }

  // FIXME: Need to enforce CONNECT; right now, doesn't require a connect.
  // FIXME: Add login handling feature
  /**
   * Manages client connections.  There is one SocketHandler per client.
   * This class is responsible for relaying communications between the
   * server and the client for which it is responsible.
   */
  protected class SocketHandler
      extends Receiver
      implements Listener, Authenticatable {
    private InputStream _input;
    private OutputStream _output;
    private Socket _socket;
    private Server _server;
    private Object _client_token;
    private boolean _authenticated = false;

    /**
     * Sets up a client communication on a given socket.
     */
    public SocketHandler( Socket sock, Server s ) throws IOException {
      super();
      _input = sock.getInputStream();
      _output = sock.getOutputStream();
      _socket = sock;
      _server = s;
      setup( this, _input );
    }

    public Object token() {
      return _client_token;
    }

    public boolean isClosed() { return _socket.isClosed(); }

    /**
     * Tests whether the supplied port is the port this handler is
     * communicating with the client over.
     *
     * @param port the port number to test.
     * @return true iff the supplied port matches the open port of this
     *  handler.
     */
    protected boolean isPort( int port ) {
      return _socket.getPort() == port;
    }

    /**
     * Close the connection with the client.
     */
    protected void close() {
      try {
        _socket.shutdownInput();
        _input.close();
      } catch (IOException e) { /* Who cares? */ }
      try {
        _socket.shutdownOutput();
        _output.close();
      } catch (IOException e) { /* Who cares? */ }
      try { _socket.close(); } catch (IOException e) { /* Who cares? */ }
    }

    public void disconnect() { close(); }

    /**
     * Gets called when messages come in from the client, and relays the
     * message to the server.  This method handles and consumes CONNECT,
     * DISCONNECT, and ERROR messages.  It is also responsible for sending
     * RECEIPTs back to the client.
     */
    public void receive( Command c, Map h, String b ) {
      if (c == Command.CONNECT) {
        String login = (String)h.get( "login" );
        String passcode = (String)h.get( "passcode" );
        try {
          _client_token = Server.this._authenticator.connect( login, passcode );
          HashMap headers = new HashMap();
          headers.put( "session", String.valueOf( this.hashCode() ) );
          transmit( Command.CONNECTED, headers, null );
          _authenticated = true;
        } catch (javax.security.auth.login.LoginException e) {
          transmit( Command.ERROR, null, "Login failed: " + e.getMessage());
        }
      } else {
        if (!_authenticated) {
          transmit( Command.ERROR, null, "Not CONNECTed, or not authorized" );
          return;
        }

        if (c == Command.DISCONNECT) {
          if (h != null) {
            String receipt = (String)h.get("receipt");
            if (receipt != null) {
              HashMap headers = new HashMap();
              headers.put( "receipt-id", receipt );
              receive( Command.RECEIPT, headers, null );
            }
          }
          _server.disconnect( this );
          this.interrupt();
          Thread.yield();
          close();
        } else if (c == Command.ERROR) {
          // Then there was an error in the client message.  Pass it back.
          error( h, b );
        } else {
          _server.receive( c, h, b, this );
        }
      }
    }

    /**
     * Called by the server; sends a message to this client.
     */
    public void message( Map headers, String body ) {
      transmit( Command.MESSAGE, headers, body );
    }

    /**
     * Called by the server; sends a receipt to this client.
     */
    public void receipt( Map headers ) {
      transmit( Command.RECEIPT, headers, null );
    }

    /**
     * Called by the server.  Sends an error to the client.
     */
    public void error( Map headers, String message ) {
      transmit( Command.ERROR, headers, message );
    }

    /**
     * Used by message(), receipt(), and error() to deliver the message to the
     * client.
     */
    private void transmit( Command c, Map h, String b ) {
      try {
        Transmitter.transmit( c, h, b, _output );
      } catch (Exception e) {
        this.interrupt();
        Thread.yield();
        close();
      }
    }
  }

  private String mapToStr( Map m ) {
    StringBuffer b = new StringBuffer("[ ");
    for (Iterator keys = m.keySet().iterator(); keys.hasNext(); ) {
      String k = keys.next().toString();
      b.append( k+" => "+m.get(k)+", " );
    }
    b.append( "]" );
    return b.toString();
  }

  /**
   * Incoming mesages from clients come here, and are delivered to listeners,
   * both intra-VM and network.
   *
   * @param c the command
   * @param h the headers
   * @param b the message
   * @param y the thing that received the message and passed it to us
   */
  protected void receive( Command c, Map h, String b, Authenticatable y ) {
    long id = (int)(Math.random() * 10000);
    try {
      // Convert to MESSAGE and distribute
      if (c == Command.COMMIT) {
        synchronized (_transactions) {
          List trans = (List)_transactions.remove(y);
          trans = new ArrayList( trans );
          for (Iterator i=trans.iterator(); i.hasNext(); ) {
            Message m = (Message)i.next();
            try {
              receive( m.command(), m.headers(), m.body(), y );
            } catch (Exception e) {
              // Don't allow listener code to break us
            }
          }
        }

      } else if (c == Command.ABORT) {
        synchronized (_transactions) {
          _transactions.remove(y);
        }

      } else if (_transactions.get( y ) != null) {
        synchronized (_transactions) {
          ((List)_transactions.get( y )).add( new Message( c, h, b ) );
        }

      } else {
        if (h == null) h = new HashMap();
        String destination = (String)h.get("destination");
        if (c == Command.SEND) {
          if (y instanceof IntraVMClient ||
              _authenticator.authorizeSend( y.token(), destination )) {
            synchronized( _listeners ) {
              List l = (List)_listeners.get( destination );
              if (l != null) {
                l = new ArrayList(l);
                for (Iterator i = l.iterator(); i.hasNext(); ) {
                  Listener sh = (Listener)i.next();
                  try {
                    sh.message( h, b );
                  } catch (Exception e) {
                    // Don't allow listener code to break us
                  }
                }
              }
            }
          } else {
            Map error_headers = new HashMap();
            error_headers.put( "message:", "authorization refused");
            error_headers.put( "type:", "send");
            error_headers.put( "channel:", destination);
            y.error( error_headers, "The message:\n-----\n"+b+
                "\n-----\nAuthentication token refused for this channel");
          }

        } else if (c == Command.SUBSCRIBE) {
          if (y instanceof IntraVMClient ||
              _authenticator.authorizeSubscribe( y.token(), destination )) {
            synchronized (_listeners ) {
              List l = (List)_listeners.get( destination );
              if (l == null) {
                l = new ArrayList();
                _listeners.put( destination, l );
              }
              if (!l.contains(y)) l.add( y );
            }
          } else {
            Map error_headers = new HashMap();
            error_headers.put( "message:", "authorization refused");
            error_headers.put( "type:", "subscription");
            error_headers.put( "channel:", destination);
            y.error( error_headers, "The message:\n-----\n"+b+
                "\n-----\nAuthentication token refused for this channel");
          }

        } else if (c == Command.UNSUBSCRIBE) {
          synchronized (_listeners) {
            List l = (List)_listeners.get( destination );
            if (l != null) l.remove( y );
          }

        } else if (c == Command.BEGIN) {
          synchronized (_transactions) {
            List trans = new ArrayList();
            _transactions.put( y, trans );
          }

        } else if (c == Command.DISCONNECT) {
          synchronized (_listeners) {
            for (Iterator i=_listeners.values().iterator(); i.hasNext(); ) {
              List l = (List)i.next();
              l.remove( y );
            }
          }
        }
      }
      if (h != null) {
        String receipt = (String)h.get("receipt");
        if (receipt != null) {
          HashMap headers = new HashMap();
          headers.put( "receipt-id", receipt );
          y.receive( Command.RECEIPT, headers, null );
        }
      }
    } catch (Exception e) {
      // Don't allow listener code to break us
    }
  }

  /**
   * Returns a Stomp client for intra-VM communications with the server.
   * This client communicates directly with the server via method() calls,
   * bypassing the network.
   */
  public Stomp getClient() {
    return new IntraVMClient( this );
  }

  /**
   * Gozirra is probably not the best choice for a stand-alone server.  If
   * you are tempted to use it as such, you might want to look at ActiveMQ,
   * which is a feature-rich MOM solution.  Gozirra is intended primarily
   * to be an ultra-light embedded messaging library.
   *
   * If you still want to run Gozirra as a stand-alone server, then you'll
   * need to know about how to call it.  The main() method takes a single
   * argument: a port to run on.  It will run until you ^C it.
   */
  public static final void main( String[] args ) {
    if (args.length != 1) {
      System.err.println("A single argument -- a port -- is required");
      System.exit(1);
    }
    int port = Integer.valueOf( args[0] ).intValue();
    System.out.println(Version.VERSION);
    try {
      new Server( port );
    } catch (Exception e) {
      System.err.println("Failed to start server");
      e.printStackTrace( System.err );
    }
  }
}


/**
 * 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.deephacks.tools4j.cli;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Path;
import javax.validation.Validation;
import javax.validation.ValidationException;

import org.deephacks.tools4j.cli.Command.Argument;

/**
 * Validator perform JSR303 bean validation on options and method arguments.
 */
final class Validator {
    static final String ARG_VIOLATION_MSG = "Argument violation";
    static final String OPT_VIOLATION_MSG = "Option violation";
    private static final javax.validation.Validator validator = Validation
            .buildDefaultValidatorFactory().getValidator();

    /**
     * This method will only be called if we know that JSR 303 1.0 Bean Validation API
     * and compliant implementation are available on classpath.
     */
    public void validateOpts(Object instance) {
        final Set<ConstraintViolation<Object>> set = validator.validate(instance);
        final StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<Object> violation : set) {
            final Path path = violation.getPropertyPath();
            final String msg = violation.getMessage();
            sb.append(path.toString()).append(" ").append(msg).append(". ");
        }
        if (sb.length() > 0) {
            // is ConstraintViolationException more appropriate,
            // letting user choose their error message?
            throw new ValidationException(OPT_VIOLATION_MSG + ": " + sb.toString());
        }
    }

    /**
     * This method will only be called if we know that JSR 303 1.1 Bean Validation API
     * and compliant implementation are available on classpath.
     *
     * Method validation was first introduced in version 1.1
     */
    public void validateArgs(List<Object> args, Object instance, Method m, Command cmd) {
        final Set<ConstraintViolation<Object>> set = validator.validateParameters(instance, m,
                args.toArray());
        final StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<Object> violation : set) {
            final Path path = violation.getPropertyPath();
            final String msg = violation.getMessage();
            String var = path.toString();
            try {
                int pos = Integer.parseInt("" + var.charAt(var.length() - 1));
                Argument arg = cmd.getArguments().get(pos);
                sb.append(arg.getName()).append(" ").append(msg).append(". ");
            } catch (Exception e) {
                sb.append(var).append(" ").append(msg).append(". ");
            }
        }
        if (sb.length() > 0) {
            // is ConstraintViolationException more appropriate,
            // letting user choose their error message?
            throw new ValidationException(ARG_VIOLATION_MSG + ": " + sb.toString());
        }
    }
}