/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.WsaConstants;
import org.apache.muse.ws.addressing.soap.SoapConstants;
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());
}
//
// create and throw WS-A DestinationUnreachable fault
//
Object[] filler = { eprNotFound, eprListing };
SoapFault wsaFault = new SoapFault(_MESSAGES.get("DestinationUnreachable", filler));
wsaFault.setCode(SoapConstants.SENDER_QNAME);
wsaFault.setSubCode(WsaConstants.DESTINATION_UNREACHABLE_FAULT_QNAME);
throw wsaFault;
}
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;
}
}