001: /**
002: * Copyright 2006 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: **/package org.araneaframework.framework.router;
016:
017: import java.util.Iterator;
018: import java.util.Map;
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.araneaframework.Environment;
022: import org.araneaframework.InputData;
023: import org.araneaframework.Message;
024: import org.araneaframework.OutputData;
025: import org.araneaframework.Path;
026: import org.araneaframework.Service;
027: import org.araneaframework.core.Assert;
028: import org.araneaframework.core.BaseService;
029: import org.araneaframework.core.NoSuchServiceException;
030: import org.araneaframework.core.StandardEnvironment;
031: import org.araneaframework.core.util.ExceptionUtil;
032: import org.araneaframework.framework.ManagedServiceContext;
033:
034: /**
035: * A router service consists of multiple child services, they form a service map.
036: * One of the services is a default one.
037: *
038: * @author "Toomas Römer" <toomas@webmedia.ee>
039: */
040: public abstract class BaseServiceRouterService extends BaseService {
041: private static final Log log = LogFactory
042: .getLog(BaseServiceRouterService.class);
043:
044: private Map serviceMap;
045: protected Object defaultServiceId;
046:
047: /**
048: * Sets the service map. Key is the id of the service, value is the service.
049: */
050: public void setServiceMap(Map serviceMap) {
051: this .serviceMap = serviceMap;
052: }
053:
054: /**
055: * Sets the default service id. The id is used as a key
056: * in the service map.
057: */
058: public void setDefaultServiceId(Object defaultServiceId) {
059: this .defaultServiceId = defaultServiceId;
060: }
061:
062: /**
063: * Initialize all the services in the service map with
064: * <code>getChildEnvironment(Object serviceId)</code>. The serviceId is the key
065: * of the service in the service map.
066: */
067: protected void init() throws Exception {
068: // adds serviceMap entries as child services
069: Iterator ite = serviceMap.entrySet().iterator();
070: while (ite.hasNext()) {
071: Map.Entry entry = (Map.Entry) ite.next();
072: _addComponent(entry.getKey(), (Service) entry.getValue(),
073: getScope(), getChildEnvironment(entry.getKey()));
074: }
075: // free extra references
076: serviceMap = null;
077: }
078:
079: protected void propagate(Message message) throws Exception {
080: Iterator ite = _getChildren().entrySet().iterator();
081: while (ite.hasNext()) {
082: Map.Entry entry = (Map.Entry) ite.next();
083: message.send(null, (Service) entry.getValue());
084: }
085: }
086:
087: /**
088: * Uses the map to route the request to the service under getServiceId(input). The id of the
089: * service is determined by <code>getServiceId(input)</code>. If the service id cannot be
090: * determined then the default id is used set via <code>setDefaultServiceId(Object)</code>.
091: */
092: protected void action(Path path, InputData input, OutputData output)
093: throws Exception {
094: Object currentServiceId = getServiceId(input);
095:
096: Assert
097: .notNull(
098: this ,
099: currentServiceId,
100: "Router found current service id to be null, which means that it could not be "
101: + "read from request and default value is not defined too.");
102:
103: if (_getChildren().containsKey(currentServiceId)) {
104: log.debug("Routing action to service '" + currentServiceId
105: + "' under router '" + getClass().getName() + "'");
106: ((Service) _getChildren().get(currentServiceId))
107: ._getService().action(path, input, output);
108: } else {
109: throw new NoSuchServiceException("Service '"
110: + currentServiceId
111: + "' was not found under router '"
112: + getClass().getName() + "'!");
113: }
114: }
115:
116: // Callbacks
117: protected Environment getChildEnvironment(Object serviceId)
118: throws Exception {
119: return new StandardEnvironment(getEnvironment(),
120: ManagedServiceContext.class,
121: new ServiceRouterContextImpl(serviceId));
122: }
123:
124: /**
125: * Returns the service id of the request. By default returns the parameter value of the request
126: * under the key <code>getServiceKey()</code>. Returns <code>defaultServiceId</code> when input
127: * has no service information specified.
128: */
129: protected Object getServiceId(InputData input) throws Exception {
130: Object id = getServiceIdFromInput(input);
131: if (id == null)
132: id = getDefaultServiceId();
133: return id;
134: }
135:
136: /**
137: * Returns the service id read from input.
138: */
139: protected Object getServiceIdFromInput(InputData input)
140: throws Exception {
141: return input.getGlobalData().get(getServiceKey());
142: }
143:
144: /**
145: * Returns the default service id.
146: */
147: protected Object getDefaultServiceId() {
148: return defaultServiceId;
149: }
150:
151: /**
152: * Every service has its own key under which the service service id can be found in the request.
153: * This method returns that key.
154: */
155: protected abstract Object getServiceKey() throws Exception;
156:
157: protected void closeService(Object serviceId) {
158: ((Service) _getChildren().get(serviceId))._getComponent()
159: .destroy();
160: _getChildren().remove(serviceId);
161: }
162:
163: protected class ServiceRouterContextImpl implements
164: ManagedServiceContext {
165: private Object currentServiceId;
166:
167: protected ServiceRouterContextImpl(Object serviceId) {
168: currentServiceId = serviceId;
169: }
170:
171: public Object getCurrentId() {
172: return currentServiceId;
173: }
174:
175: public Service getService(Object id) {
176: return (Service) _getChildren().get(id);
177: }
178:
179: public Service addService(Object id, Service service) {
180: try {
181: _addComponent(id, service, null,
182: getChildEnvironment(id));
183: } catch (Exception e) {
184: throw ExceptionUtil.uncheckException(e);
185: }
186: return service;
187: }
188:
189: public Service addService(Object id, Service service,
190: Long timeToLive) {
191: Service result = addService(id, service);
192: if (log.isWarnEnabled()) {
193: log
194: .warn(getClass().getName()
195: + ".addService(Object id, Service service, Long timeToLive) ignores timeToLive attribute."
196: + "Just addService(Object id, Service service) should be used.");
197: }
198: return result;
199: }
200:
201: public void close(Object id) {
202: closeService(id);
203: }
204: }
205: }
|