001 package org.apache.ojb.broker.locking;
002
003 /* Copyright 2004-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import java.io.BufferedOutputStream;
019 import java.io.ByteArrayOutputStream;
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.io.ObjectInputStream;
023 import java.io.ObjectOutputStream;
024 import java.io.Serializable;
025 import java.net.HttpURLConnection;
026 import java.net.MalformedURLException;
027 import java.net.ProtocolException;
028 import java.net.URL;
029
030 import org.apache.ojb.broker.util.configuration.Configurable;
031 import org.apache.ojb.broker.util.configuration.Configuration;
032 import org.apache.ojb.broker.util.configuration.ConfigurationException;
033 import org.apache.ojb.broker.util.logging.Logger;
034 import org.apache.ojb.broker.util.logging.LoggerFactory;
035
036 /**
037 * This implementation of the {@link LockManager} interface supports locking
038 * in distributed environments in combination with a specific lock servlet.
039 *
040 * @see LockManagerServlet
041 * @version $Id: LockManagerRemoteImpl.java,v 1.1 2007-08-24 22:17:41 ewestfal Exp $
042 */
043 public class LockManagerRemoteImpl implements LockManager, Configurable
044 {
045 private Logger log = LoggerFactory.getLogger(LockManagerRemoteImpl.class);
046
047 public static final byte METHOD_READ_LOCK = 'a';
048 public static final byte METHOD_WRITE_LOCK = 's';
049 public static final byte METHOD_UPGRADE_LOCK = 'u';
050 public static final byte METHOD_CHECK_READ = 'r';
051 public static final byte METHOD_CHECK_WRITE = 'w';
052 public static final byte METHOD_CHECK_UPGRADE = 'v';
053 public static final byte METHOD_RELEASE_SINGLE_LOCK = 'e';
054 public static final byte METHOD_RELEASE_LOCKS = 'x';
055 public static final byte METHOD_LOCK_INFO = 'i';
056 public static final byte METHOD_LOCK_TIMEOUT = 't';
057 public static final byte METHOD_LOCK_TIMEOUT_SET = 'y';
058 public static final byte METHOD_BLOCK_TIMEOUT = 'c';
059 public static final byte METHOD_BLOCK_TIMEOUT_SET = 'd';
060
061 private static URL lockservlet = null;
062
063 public LockManagerRemoteImpl()
064 {
065 }
066
067 /**
068 * @see org.apache.ojb.broker.util.configuration.Configurable#configure(org.apache.ojb.broker.util.configuration.Configuration)
069 */
070 public void configure(Configuration pConfig) throws ConfigurationException
071 {
072 String url = pConfig.getString("LockServletUrl", "http://127.0.0.1:8080/ojb-lockserver");
073 log.info("Lock server servlet URL: " + url);
074 try
075 {
076 lockservlet = new URL(url);
077 }
078 catch(MalformedURLException e)
079 {
080 throw new ConfigurationException("Invalid LockServlet Url was specified: " + url, e);
081 }
082
083 }
084
085 /**
086 * noop
087 * @param timeout
088 */
089 public void setLockTimeout(long timeout)
090 {
091 // LockInfo info = new LockInfo(timeout, METHOD_LOCK_TIMEOUT_SET);
092 // try
093 // {
094 // byte[] requestBarr = serialize(info);
095 // performRequestObject(requestBarr);
096 // }
097 // catch(Throwable t)
098 // {
099 // throw new LockRuntimeException("Can't set locking timeout", t);
100 // }
101 }
102
103 public long getLockTimeout()
104 {
105 LockInfo info = new LockInfo(METHOD_LOCK_TIMEOUT);
106 try
107 {
108 byte[] requestBarr = serialize(info);
109 return performRequestLong(requestBarr);
110 }
111 catch(Throwable t)
112 {
113 throw new LockRuntimeException("Can't get locking info", t);
114 }
115 }
116
117 public long getBlockTimeout()
118 {
119 LockInfo info = new LockInfo(METHOD_BLOCK_TIMEOUT);
120 try
121 {
122 byte[] requestBarr = serialize(info);
123 return performRequestLong(requestBarr);
124 }
125 catch(Throwable t)
126 {
127 throw new LockRuntimeException("Can't get block timeout value", t);
128 }
129 }
130
131 /**
132 * noop
133 */
134 public void setBlockTimeout(long timeout)
135 {
136 // LockInfo info = new LockInfo(timeout, METHOD_BLOCK_TIMEOUT_SET);
137 // try
138 // {
139 // byte[] requestBarr = serialize(info);
140 // performRequestObject(requestBarr);
141 // }
142 // catch(Throwable t)
143 // {
144 // throw new LockRuntimeException("Can't set block timeout value", t);
145 // }
146 }
147
148 public String getLockInfo()
149 {
150 LockInfo info = new LockInfo(METHOD_LOCK_INFO);
151 try
152 {
153 byte[] requestBarr = serialize(info);
154 return performRequestString(requestBarr);
155 }
156 catch(Throwable t)
157 {
158 throw new LockRuntimeException("Can't get locking info", t);
159 }
160 }
161
162 public boolean readLock(Object key, Object resourceId, int isolationLevel)
163 {
164 LockInfo info = new LockInfo(key, resourceId, isolationLevel, METHOD_READ_LOCK);
165 try
166 {
167 byte[] requestBarr = serialize(info);
168 return performRequest(requestBarr);
169 }
170 catch(Throwable t)
171 {
172 throw new LockRuntimeException("Cannot check read lock for '"
173 + resourceId + "' using key '" + key + "'", t);
174 }
175 }
176
177 public boolean releaseLock(Object key, Object resourceId)
178 {
179 LockInfo info = new LockInfo(key, resourceId, METHOD_RELEASE_SINGLE_LOCK);
180 try
181 {
182 byte[] requestBarr = serialize(info);
183 return performRequest(requestBarr);
184 }
185 catch(Throwable t)
186 {
187 throw new LockRuntimeException("Cannot remove write lock for '"
188 + resourceId + "' using key '" + key + "'", t);
189 }
190 }
191
192 // public boolean removeReader(Object key, Object resourceId)
193 // {
194 // LockInfo info = new LockInfo(key, resourceId, METHOD_RELEASE_SINGLE_LOCK);
195 // try
196 // {
197 // byte[] requestBarr = serialize(info);
198 // return performRequest(requestBarr);
199 // }
200 // catch(Throwable t)
201 // {
202 // throw new LockRuntimeException("Cannot remove read lock for '"
203 // + resourceId + "' using key '" + key + "'", t);
204 // }
205 // }
206
207 public void releaseLocks(Object key)
208 {
209 LockInfo info = new LockInfo(key, null, METHOD_RELEASE_LOCKS);
210 try
211 {
212 byte[] requestBarr = serialize(info);
213 performRequest(requestBarr);
214 }
215 catch(Throwable t)
216 {
217 throw new LockRuntimeException("Cannot release locks using owner key '" + key + "'", t);
218 }
219 }
220
221 public boolean writeLock(Object key, Object resourceId, int isolationLevel)
222 {
223 LockInfo info = new LockInfo(key, resourceId, isolationLevel, METHOD_WRITE_LOCK);
224 try
225 {
226 byte[] requestBarr = serialize(info);
227 return performRequest(requestBarr);
228 }
229 catch(Throwable t)
230 {
231 throw new LockRuntimeException("Cannot set write lock for '"
232 + resourceId + "' using key '" + key + "'", t);
233 }
234 }
235
236 public boolean upgradeLock(Object key, Object resourceId, int isolationLevel)
237 {
238 LockInfo info = new LockInfo(key, resourceId, isolationLevel, METHOD_UPGRADE_LOCK);
239 try
240 {
241 byte[] requestBarr = serialize(info);
242 return performRequest(requestBarr);
243 }
244 catch(Throwable t)
245 {
246 throw new LockRuntimeException("Cannot set write lock for '"
247 + resourceId + "' using key '" + key + "'", t);
248 }
249 }
250
251 public boolean hasRead(Object key, Object resourceId)
252 {
253 try
254 {
255 byte[] requestBarr = serialize(new LockInfo(key, resourceId, METHOD_CHECK_READ));
256 return performRequest(requestBarr);
257 }
258 catch(Throwable t)
259 {
260 throw new LockRuntimeException("Cannot check read lock for '"
261 + resourceId + "' using key '" + key + "'", t);
262 }
263 }
264
265 public boolean hasWrite(Object key, Object resourceId)
266 {
267 try
268 {
269 byte[] requestBarr = serialize(new LockInfo(key, resourceId, METHOD_CHECK_WRITE));
270 return performRequest(requestBarr);
271 }
272 catch(Throwable t)
273 {
274 throw new LockRuntimeException("Cannot check write lock for '"
275 + resourceId + "' using key '" + key + "'", t);
276 }
277 }
278
279 public boolean hasUpgrade(Object key, Object resourceId)
280 {
281 try
282 {
283 byte[] requestBarr = serialize(new LockInfo(key, resourceId, METHOD_CHECK_UPGRADE));
284 return performRequest(requestBarr);
285 }
286 catch(Throwable t)
287 {
288 throw new LockRuntimeException("Cannot check write lock for '"
289 + resourceId + "' using key '" + key + "'", t);
290 }
291 }
292
293 private HttpURLConnection getHttpUrlConnection()
294 throws MalformedURLException, IOException, ProtocolException
295 {
296 URL lockserver = getLockserverUrl();
297 HttpURLConnection conn = (HttpURLConnection) lockserver.openConnection();
298
299 conn.setDoInput(true);
300 conn.setDoOutput(true);
301 conn.setRequestMethod("POST");
302 conn.setAllowUserInteraction(false);
303 conn.setUseCaches(false);
304 return conn;
305 }
306
307 private URL getLockserverUrl()
308 {
309 return lockservlet;
310 }
311
312 public byte[] serialize(Object obj) throws IOException
313 {
314 ByteArrayOutputStream bao = new ByteArrayOutputStream();
315 ObjectOutputStream oos = new ObjectOutputStream(bao);
316 oos.writeObject(obj);
317 oos.close();
318 bao.close();
319 byte[] result = bao.toByteArray();
320 return result;
321 }
322
323 private boolean performRequest(byte[] requestBarr) throws IOException, ClassNotFoundException
324 {
325 Object result = performRequestObject(requestBarr);
326 if(result instanceof Boolean)
327 {
328 return ((Boolean) result).booleanValue();
329 }
330 else
331 {
332 throw new LockRuntimeException("Remote lock server error, expect return value of type 'Boolean'");
333 }
334 }
335
336 private String performRequestString(byte[] requestBarr) throws IOException, ClassNotFoundException
337 {
338 Object result = performRequestObject(requestBarr);
339 if(result instanceof String)
340 {
341 return (String) result;
342 }
343 else
344 {
345 throw new LockRuntimeException("Remote lock server error, expect return value of type 'String'");
346 }
347 }
348
349 private long performRequestLong(byte[] requestBarr) throws IOException, ClassNotFoundException
350 {
351 Object result = performRequestObject(requestBarr);
352 if(result instanceof Long)
353 {
354 return ((Long) result).longValue();
355 }
356 else
357 {
358 throw new LockRuntimeException("Remote lock server error, expect return value of type 'String'");
359 }
360 }
361
362 private Object performRequestObject(byte[] requestBarr) throws IOException, ClassNotFoundException
363 {
364 HttpURLConnection conn = getHttpUrlConnection();
365
366 //post request
367 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
368 out.write(requestBarr, 0, requestBarr.length);
369 out.flush();
370
371 // read result from
372 InputStream in = conn.getInputStream();
373 ObjectInputStream ois = new ObjectInputStream(in);
374 Object result = ois.readObject();
375
376 // cleanup
377 ois.close();
378 out.close();
379 conn.disconnect();
380
381 if(result instanceof Throwable)
382 {
383 throw new LockRuntimeException("Remote lock server error", (Throwable) result);
384 }
385 else
386 {
387 return result;
388 }
389 }
390
391 public static final class LockInfo implements Serializable
392 {
393 public Object key;
394 public Object resourceId;
395 public int isolationLevel;
396 public byte methodName;
397 public long lockTimeout;
398 public long blockTimeout;
399
400 public LockInfo(byte methodName)
401 {
402 this.methodName = methodName;
403 }
404
405 public LockInfo(Object key, Object resourceId, byte methodName)
406 {
407 this.key = key;
408 this.resourceId = resourceId;
409 this.methodName = methodName;
410 }
411
412 public LockInfo(Object key, Object resourceId, int isolationLevel, byte methodName)
413 {
414 this.key = key;
415 this.resourceId = resourceId;
416 this.isolationLevel = isolationLevel;
417 this.methodName = methodName;
418 }
419
420 // public LockInfo(long timeout, byte methodName)
421 // {
422 // if(methodName == METHOD_LOCK_TIMEOUT_SET)
423 // {
424 // this.lockTimeout = timeout;
425 // }
426 // else
427 // {
428 // this.blockTimeout = timeout;
429 // }
430 // this.methodName = methodName;
431 // }
432 }
433 }