package org.codehaus.xfire.service;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.xml.namespace.QName;

import org.codehaus.xfire.AbstractContext;

/**
 * Represents an description of a service. A service consists of a number of <code>OperationInfo</code> objects, a
 * qualified name, and a service class.
 *
 * @author <a href="mailto:poutsma@mac.com">Arjen Poutsma</a>
 * @see OperationInfo
 */
public class ServiceInfo
    extends AbstractContext
    implements Visitable
{
    private QName name;
    private Map operations = new HashMap();
    private Class serviceClass;
    private QName portType;
    private Map endpoints = new HashMap();
    
    /**
     * Initializes a new instance of the <code>ServiceInfo</code> class with the given qualified name and service
     * class.
     *
     * @param name         the qualified name.
     * @param serviceClass the service class.
     */
    public ServiceInfo(QName name, QName portType, Class serviceClass)
    {
        this.name = name;
        this.portType = portType;
        this.serviceClass = serviceClass;
    }

    /**
     * Acceps the given visitor. Iterates over all operation infos.
     *
     * @param visitor the visitor.
     */
    public void accept(Visitor visitor)
    {
        visitor.startService(this);
        for (Iterator iterator = operations.values().iterator(); iterator.hasNext();)
        {
            OperationInfo operationInfo = (OperationInfo) iterator.next();
            operationInfo.accept(visitor);
        }
        visitor.endService(this);
    }

    /**
     * Adds an operation to this service.
     *
     * @param name the qualified name of the operation.
     * @return the operation.
     */
    public OperationInfo addOperation(String name, Method method)
    {
        if ((name == null) || (name.length() == 0))
        {
            throw new IllegalArgumentException("Invalid name [" + name + "]");
        }
        if (operations.containsKey(name))
        {
            throw new IllegalArgumentException("An operation with name [" + name + "] already exists in this service");
        }

        OperationInfo operation = new OperationInfo(name, method, this);
        addOperation(operation);
        return operation;
    }

    /**
     * Adds an operation to this service.
     *
     * @param operation the operation.
     */
    void addOperation(OperationInfo operation)
    {
        operations.put(operation.getName(), operation);
    }

    /**
     * Returns the qualified name of the service descriptor.
     *
     * @return the qualified name.
     */
    public QName getName()
    {
        return name;
    }

    /**
     * Sets the qualified name of the service descriptor.
     *
     * @param name the new qualified name.
     */
    public void setName(QName name)
    {
        this.name = name;
    }

    /**
     * Returns the operation info with the given name, if found.
     *
     * @param name the name.
     * @return the operation; or <code>null</code> if not found.
     */
    public OperationInfo getOperation(String name)
    {
        return (OperationInfo) operations.get(name);
    }

    /**
     * Returns all operations for this service.
     *
     * @return all operations.
     */
    public Collection getOperations()
    {
        return Collections.unmodifiableCollection(operations.values());
    }

    /**
     * Returns the service class of the service descriptor.
     *
     * @return
     */
    public Class getServiceClass()
    {
        return serviceClass;
    }

    /**
     * Removes an operation from this service.
     *
     * @param name the operation name.
     */
    public void removeOperation(String name)
    {
        operations.remove(name);
    }

    public QName getPortType()
    {
        return portType;
    }

    public void setPortType(QName portType)
    {
        this.portType = portType;
    }

    public Collection getEndpoints()
    {
        return Collections.unmodifiableCollection(endpoints.values());
    }

    public void addEndpoint(Endpoint endpoint)
    {
        endpoints.put(endpoint.getName(), endpoint);
    }

    public Endpoint getEndpoint(QName name)
    {
        return (Endpoint) endpoints.get(name);
    }

    public void addEndpoint(QName name, String bindingId, String address)
    {
        addEndpoint(new Endpoint(name, bindingId, address));
    }

}
@@ -63,16 +63,44 @@
 Method;%0A
+import java.util.ArrayList;%0A
 import j
@@ -203,16 +203,39 @@
 erator;%0A
+import java.util.List;%0A
 import j
@@ -698,21 +698,74 @@
 ate 
-Map o
+List operations = new ArrayList();%0A    private Map nameToO
 peration
 s = 
@@ -756,25 +756,24 @@
 eToOperation
-s
  = new HashM
@@ -1557,25 +1557,31 @@
 rator = 
-o
+nameToO
 peration
 s.values
@@ -1564,33 +1564,32 @@
  nameToOperation
-s
 .values().iterat
@@ -2180,25 +2180,31 @@
     if (
-o
+nameToO
 peration
 s.contai
@@ -2195,17 +2195,16 @@
 peration
-s
 .contain
@@ -2660,25 +2660,31 @@
         
-o
+nameToO
 peration
 s.put(op
@@ -2675,17 +2675,16 @@
 peration
-s
 .put(ope
@@ -2709,24 +2709,59 @@
 operation);%0A
+        operations.add(operation);%0A
     %7D%0A%0A    /
@@ -3408,36 +3408,451 @@
 fo) 
-operations.get(name);%0A    %7D%0A
+nameToOperation.get(name);%0A    %7D%0A%0A    public Collection getOperations(String name)%0A    %7B%0A        List operations = new ArrayList();%0A        for (Iterator itr = getOperations().iterator(); itr.hasNext();)%0A        %7B%0A            OperationInfo candidate = (OperationInfo) itr.next();%0A            if (candidate.getName().equals(name))%0A            %7B%0A                operations.add(candidate);%0A            %7D%0A        %7D%0A        return operations;%0A    %7D
 %0A   
@@ -4054,25 +4054,16 @@
 erations
-.values()
 );%0A    %7D
@@ -4407,25 +4407,31 @@
         
-o
+nameToO
 peration
 s.remove
@@ -4422,17 +4422,16 @@
 peration
-s
 .remove(

Allow multiple operations with the same name