/*=============================================================================*
* Copyright 2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*=============================================================================*/
package org.apache.muse.core.routing;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Logger;
import org.w3c.dom.Element;
import org.apache.muse.core.Environment;
import org.apache.muse.core.Resource;
import org.apache.muse.core.ResourceManager;
import org.apache.muse.core.SimpleResourceManager;
import org.apache.muse.core.descriptor.ResourceDefinition;
import org.apache.muse.util.LoggingUtils;
import org.apache.muse.util.messages.Messages;
import org.apache.muse.util.messages.MessagesFactory;
import org.apache.muse.ws.addressing.EndpointReference;
import org.apache.muse.ws.addressing.MessageHeaders;
import org.apache.muse.ws.addressing.soap.SoapFault;
/**
*
* SimpleResourceRouter is Muse's default implementation of a router that uses
* the implied resource pattern to delegate requests to resources. It uses
* the WS-A header data to map the request to a particular resource in its
* {@linkplain ResourceManager ResourceManager}.
*
* @author Dan Jemiolo (danj)
*
*/
public class SimpleResourceRouter implements ResourceRouter
{
//
// Used to lookup all exception messages
//
private static Messages _MESSAGES = MessagesFactory.get(SimpleResourceRouter.class);
private Environment _environment = null;
private boolean _hasBeenInitialized = false;
private boolean _hasBeenShutdown = false;
private Logger _log = null;
//
// optional persistence mechanism for saving/re-loading router entries
//
private RouterPersistence _persistence = null;
//
// all of the ResourceDefinition objects for the resource types that
// are controlled by this router
//
private Collection _resourceDefinitions = null;
//
// the container for all implied resources
//
private ResourceManager _resourceManager = null;
/**
*
* This method can be overridden to provide an alternate implementation
* of the ResourceManager component to the router.
*
* @return An instance of SimpleResourceManager.
*
*/
protected ResourceManager createResourceManager()
{
return new SimpleResourceManager();
}
public Environment getEnvironment()
{
return _environment;
}
public Logger getLog()
{
return _log;
}
public RouterPersistence getPersistence()
{
return _persistence;
}
public Collection getResourceDefinitions()
{
return _resourceDefinitions;
}
public ResourceManager getResourceManager()
{
return _resourceManager;
}
/**
*
* Queries the Environment to get the WS-A EPR being targeted by the
* current request and then does a lookup in the ResourceManager with
* that EPR. This method is essential to all routing activity. The
* resource returned is guaranteed to be the resource specified by the
* client, but it is not guaranteed to support the specified operation.
*
* @return The resource whose EPR maps to the WS-A data in the current
* request.
*
* @throws SoapFault
* <ul>
* <li>If the EPR (including any unique reference properties) is
* not associated with any resource instance.</li>
* </ul>
*
* @see MessageHeaders#getToAddress()
* @see ResourceManager#getResource(EndpointReference)
*
*/
protected Resource getTargetResource()
throws SoapFault
{
ResourceManager manager = getResourceManager();
Environment env = getEnvironment();
MessageHeaders wsa = env.getAddressingContext();
if (wsa == null)
throw new RuntimeException(_MESSAGES.get("NoAddressingContext"));
EndpointReference epr = wsa.getToAddress();
Resource resource = manager.getResource(epr);
if (resource == null)
{
//
// construct an error message that has a formatted list of
// all of the valid EPRs so that users can determine what
// was wrong with the EPR they provided
//
StringBuffer eprNotFound = new StringBuffer(512);
eprNotFound.append("\n\n");
eprNotFound.append(epr);
eprNotFound.append('\n');
Iterator i = manager.getResourceEPRs();
StringBuffer eprListing = new StringBuffer(1024);
eprListing.append('\n');
while (i.hasNext())
{
eprListing.append('\n');
eprListing.append(i.next());
}
Object[] filler = { eprNotFound, eprListing };
throw new SoapFault(_MESSAGES.get("DestinationUnreachable", filler));
}
return resource;
}
public boolean hasBeenInitialized()
{
return _hasBeenInitialized;
}
public boolean hasBeenShutdown()
{
return _hasBeenShutdown;
}
/**
*
* {@inheritDoc}
* <br><br>
* This implementation performs initialization using the steps below.
* <br>
* <ol>
* <li>Make sure a Logger has been provided.</li>
* <li>Make sure an Environment has been provided.</li>
* <li>Create the ResourceManager component.</li>
* <li>Create any resources that are supposed to be instantiated at
* startup.</li>
* </ol>
*
*/
public void initialize()
throws SoapFault
{
Logger log = getLog();
if (log == null)
throw new IllegalStateException(_MESSAGES.get("NoLogger"));
Environment env = getEnvironment();
if (env == null)
throw new IllegalStateException(_MESSAGES.get("NoEnvironment"));
Collection definitions = getResourceDefinitions();
Iterator i = definitions.iterator();
while (i.hasNext())
{
ResourceDefinition next = (ResourceDefinition)i.next();
next.setLog(log);
}
//
// tell the resource manager about all our resource types
//
_resourceManager = createResourceManager();
_resourceManager.setEnvironment(env);
_resourceManager.addResourceDefinitions(definitions);
//
// add persistence component to manager, if one exists
//
RouterPersistence persistence = getPersistence();
if (persistence != null)
{
//
// first, ask the persistence component to reload any resources
// that were saved last time we shut down
//
persistence.setResourceManager(_resourceManager);
persistence.reload();
//
// then add the component as a listener so it can save any new
// resources and cleanup resources that were destroyed
//
_resourceManager.addListener(persistence);
}
_resourceManager.initialize();
getLog().info(_MESSAGES.get("RouterIsInitialized"));
_hasBeenInitialized = true;
}
public Element invoke(Element soapBody)
{
Resource resource = null;
try
{
resource = getTargetResource();
}
catch (SoapFault fault)
{
return fault.toXML();
}
return resource.invoke(soapBody);
}
public void setEnvironment(Environment environment)
{
if (environment == null)
throw new NullPointerException(_MESSAGES.get("NullEnvironment"));
_environment = environment;
}
public void setLog(Logger log)
{
if (log == null)
throw new NullPointerException(_MESSAGES.get("NullLogger"));
_log = log;
}
public void setPersistence(RouterPersistence persistence)
{
_persistence = persistence;
}
public void setResourceDefinitions(Collection resourceDefinitions)
{
if (resourceDefinitions == null)
throw new NullPointerException(_MESSAGES.get("NullResourceDefinitions"));
_resourceDefinitions = resourceDefinitions;
}
public void setResourceManager(ResourceManager resourceManager)
{
if (resourceManager == null)
throw new NullPointerException(_MESSAGES.get("NullResourceManager"));
_resourceManager = resourceManager;
}
/**
*
* {@inheritDoc}
* <br><br>
* This implementation iterates over the collection of resources in
* the ResourceManager and destroys each one. If one destructor fails,
* it is logged and we move on to the next resource.
*
* @see #getResourceManager()
*
*/
public void shutdown()
{
try
{
getResourceManager().shutdown();
}
catch (SoapFault error)
{
LoggingUtils.logError(getLog(), error);
}
_hasBeenShutdown = true;
}
}