KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > remote > service > BaseRemoteService


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.remote.service;
21
22 import java.util.Collections JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Map JavaDoc;
25
26 import org.apache.cayenne.CayenneRuntimeException;
27 import org.apache.cayenne.DataChannel;
28 import org.apache.cayenne.access.ClientServerChannel;
29 import org.apache.cayenne.access.DataDomain;
30 import org.apache.cayenne.conf.Configuration;
31 import org.apache.cayenne.conf.DefaultConfiguration;
32 import org.apache.cayenne.remote.ClientMessage;
33 import org.apache.cayenne.remote.RemoteService;
34 import org.apache.cayenne.remote.RemoteSession;
35 import org.apache.cayenne.util.Util;
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38
39 /**
40  * A generic implementation of an RemoteService. Subclasses can be customized to work with
41  * different remoting mechanisms, such as Hessian or JAXRPC.
42  *
43  * @since 1.2
44  * @author Andrus Adamchik
45  */

46 public abstract class BaseRemoteService implements RemoteService {
47
48     public static final String JavaDoc EVENT_BRIDGE_FACTORY_PROPERTY = "cayenne.RemoteService.EventBridge.factory";
49
50     // keep logger non-static so that it could be garbage collected with this instance..
51
private final Log logObj = LogFactory.getLog(BaseRemoteService.class);
52
53     protected DataDomain domain;
54
55     protected String JavaDoc eventBridgeFactoryName;
56     protected Map JavaDoc eventBridgeParameters;
57
58     public String JavaDoc getEventBridgeFactoryName() {
59         return eventBridgeFactoryName;
60     }
61
62     public Map JavaDoc getEventBridgeParameters() {
63         return eventBridgeParameters != null ? Collections
64                 .unmodifiableMap(eventBridgeParameters) : Collections.EMPTY_MAP;
65     }
66
67     /**
68      * A method that sets up a service, initializing Cayenne stack. Should be invoked by
69      * subclasses from their appropriate service lifecycle methods.
70      */

71     protected void initService(Map JavaDoc properties) throws CayenneRuntimeException {
72
73         // start Cayenne service
74
logObj.debug(this.getClass().getName() + " is starting");
75
76         initCayenneStack(properties);
77         initEventBridgeParameters(properties);
78
79         logObj.debug(getClass().getName() + " started");
80     }
81
82     /**
83      * Shuts down this service. Should be invoked by subclasses from their appropriate
84      * service lifecycle methods.
85      */

86     protected void destroyService() {
87         logObj.debug(getClass().getName() + " destroyed");
88     }
89
90     /**
91      * Returns a DataChannel that is a parent of all session DataChannels.
92      */

93     public DataChannel getRootChannel() {
94         return domain;
95     }
96
97     /**
98      * Creates a new ServerSession with a dedicated DataChannel.
99      */

100     protected abstract ServerSession createServerSession();
101
102     /**
103      * Creates a new ServerSession based on a shared DataChannel.
104      *
105      * @param name shared session name used to lookup a shared DataChannel.
106      */

107     protected abstract ServerSession createServerSession(String JavaDoc name);
108
109     /**
110      * Returns a ServerSession object that represents Cayenne-related state associated
111      * with the current session. If ServerSession hasn't been previously saved, returns
112      * null.
113      */

114     protected abstract ServerSession getServerSession();
115
116     public RemoteSession establishSession() {
117         logObj.debug("Session requested by client");
118
119         RemoteSession session = createServerSession().getSession();
120
121         logObj.debug("Established client session: " + session);
122         return session;
123     }
124
125     public RemoteSession establishSharedSession(String JavaDoc name) {
126         logObj.debug("Shared session requested by client. Group name: " + name);
127
128         if (name == null) {
129             throw new CayenneRuntimeException("Invalid null shared session name");
130         }
131
132         return createServerSession(name).getSession();
133     }
134
135     public Object JavaDoc processMessage(ClientMessage message) throws Throwable JavaDoc {
136
137         if (message == null) {
138             throw new IllegalArgumentException JavaDoc("Null client message.");
139         }
140
141         ServerSession handler = getServerSession();
142
143         if (handler == null) {
144             throw new MissingSessionException("No session associated with request.");
145         }
146
147         logObj.debug("processMessage, sessionId: " + handler.getSession().getSessionId());
148
149         // intercept and log exceptions
150
try {
151             return DispatchHelper.dispatch(handler.getChannel(), message);
152         }
153         catch (Throwable JavaDoc th) {
154             th = Util.unwindException(th);
155             logObj.info("error processing message", th);
156
157             // throw exception that will likely be propagated to the client...
158
// recast the exception to a guaranteed serializable form
159

160             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
161             buffer.append("Exception processing message ").append(
162                     message.getClass().getName());
163
164             String JavaDoc exceptionText = th.getLocalizedMessage();
165             if (exceptionText != null) {
166                 buffer.append(". Root cause: ").append(exceptionText);
167             }
168
169             throw new CayenneRuntimeException(buffer.toString());
170         }
171     }
172
173     protected RemoteSession createRemoteSession(
174             String JavaDoc sessionId,
175             String JavaDoc name,
176             boolean enableEvents) {
177         RemoteSession session = (enableEvents) ? new RemoteSession(
178                 sessionId,
179                 eventBridgeFactoryName,
180                 eventBridgeParameters) : new RemoteSession(sessionId);
181
182         session.setName(name);
183         return session;
184     }
185
186     /**
187      * Creates a server-side channel that will handle all client requests. For shared
188      * sessions the same channel instance is reused for the entire group of clients. For
189      * dedicated sessions, one channel per client is created. <p/> This implementation
190      * returns {@link ClientServerChannel} instance wrapping a DataContext. Subclasses may
191      * override the method to customize channel creation. For instance they may wrap
192      * channel in the custom interceptors to handle transactions or security.
193      */

194     protected DataChannel createChannel() {
195         return new ClientServerChannel(domain);
196     }
197
198     /**
199      * Sets up Cayenne stack.
200      */

201     protected void initCayenneStack(Map JavaDoc properties) {
202         Configuration cayenneConfig = new DefaultConfiguration(
203                 Configuration.DEFAULT_DOMAIN_FILE);
204
205         try {
206             cayenneConfig.initialize();
207             cayenneConfig.didInitialize();
208         }
209         catch (Exception JavaDoc ex) {
210             throw new CayenneRuntimeException("Error starting Cayenne", ex);
211         }
212
213         // TODO (Andrus 10/15/2005) this assumes that mapping has a single domain...
214
// do something about multiple domains
215
this.domain = cayenneConfig.getDomain();
216     }
217
218     /**
219      * Initializes EventBridge parameters for remote clients peer-to-peer communications.
220      */

221     protected void initEventBridgeParameters(Map JavaDoc properties) {
222         String JavaDoc eventBridgeFactoryName = (String JavaDoc) properties
223                 .get(BaseRemoteService.EVENT_BRIDGE_FACTORY_PROPERTY);
224
225         if (eventBridgeFactoryName != null) {
226
227             Map JavaDoc eventBridgeParameters = new HashMap JavaDoc(properties);
228             eventBridgeParameters.remove(BaseRemoteService.EVENT_BRIDGE_FACTORY_PROPERTY);
229
230             this.eventBridgeFactoryName = eventBridgeFactoryName;
231             this.eventBridgeParameters = eventBridgeParameters;
232         }
233     }
234 }
235
Popular Tags