001 package org.apache.ojb.odmg.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.net.HttpURLConnection;
025 import java.net.MalformedURLException;
026 import java.net.ProtocolException;
027 import java.net.URL;
028 import java.util.Collection;
029
030 import org.apache.ojb.broker.Identity;
031 import org.apache.ojb.broker.PersistenceBroker;
032 import org.apache.ojb.broker.PersistenceBrokerException;
033 import org.apache.ojb.broker.util.configuration.Configurable;
034 import org.apache.ojb.broker.util.configuration.Configuration;
035 import org.apache.ojb.broker.util.configuration.ConfigurationException;
036 import org.apache.ojb.broker.util.logging.Logger;
037 import org.apache.ojb.broker.util.logging.LoggerFactory;
038 import org.apache.ojb.odmg.TransactionImpl;
039 import org.apache.ojb.odmg.TxManagerFactory;
040
041 /**
042 * Servlet based lock mechanism for usage in distributed environment.
043 * @author Thomas Mahler
044 * @version $Id: RemoteLockMapImpl.java,v 1.1 2007-08-24 22:17:28 ewestfal Exp $
045 */
046 public class RemoteLockMapImpl implements LockMap, Configurable
047 {
048 private Logger log = LoggerFactory.getLogger(RemoteLockMapImpl.class);
049
050 private static URL lockservlet = null;
051
052 /**
053 * obtain a PersistenceBroker instance.
054 */
055 private PersistenceBroker getBroker()
056 {
057 return TxManagerFactory.instance().getCurrentTransaction().getBroker();
058 }
059
060 /**
061 * returns the LockEntry for the Writer of object obj.
062 * If now writer exists, null is returned.
063 */
064 public LockEntry getWriter(Object obj)
065 {
066 PersistenceBroker broker = getBroker();
067 Identity oid = new Identity(obj, broker);
068
069 LockEntry result = null;
070 try
071 {
072 result = getWriterRemote(oid);
073 }
074 catch (Throwable e)
075 {
076 log.error(e);
077 }
078 return result;
079 }
080
081 private LockEntry getWriterRemote(Identity oid)
082 throws
083 MalformedURLException,
084 IOException,
085 ProtocolException,
086 ClassNotFoundException
087 {
088 byte selector = (byte) 'w';
089 byte[] requestBarr = buildRequestArray(oid, selector);
090
091 HttpURLConnection conn = getHttpUrlConnection();
092
093 //post request
094 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
095 out.write(requestBarr,0,requestBarr.length);
096 out.flush();
097 out.close();
098
099 // read result from
100 InputStream in = conn.getInputStream();
101 ObjectInputStream ois = new ObjectInputStream(in);
102 LockEntry result = (LockEntry) ois.readObject();
103
104 // cleanup
105 ois.close();
106 conn.disconnect();
107 return result;
108 }
109
110 private HttpURLConnection getHttpUrlConnection()
111 throws MalformedURLException, IOException, ProtocolException
112 {
113 URL lockserver = getLockserverUrl();
114 HttpURLConnection conn= (HttpURLConnection) lockserver.openConnection();
115
116 conn.setDoInput(true);
117 conn.setDoOutput(true);
118 conn.setRequestMethod("POST");
119 conn.setAllowUserInteraction(false);
120 conn.setUseCaches(false);
121 return conn;
122 }
123
124 private byte[] buildRequestArray(Object object, byte selector) throws IOException
125 {
126 byte[] serialObj = serialize(object);
127 int len = serialObj.length;
128 byte[] requestBarr = new byte[len + 1];
129 requestBarr[0] = selector;
130 System.arraycopy(serialObj,0,requestBarr,1,len);
131 return requestBarr;
132 }
133
134
135 private URL getLockserverUrl() throws MalformedURLException
136 {
137 return lockservlet;
138 }
139
140
141
142 /**
143 * returns a collection of Reader LockEntries for object obj.
144 * If now LockEntries could be found an empty Vector is returned.
145 */
146 public Collection getReaders(Object obj)
147 {
148 Collection result = null;
149 try
150 {
151 Identity oid = new Identity(obj, getBroker());
152 byte selector = (byte) 'r';
153 byte[] requestBarr = buildRequestArray(oid, selector);
154
155 HttpURLConnection conn = getHttpUrlConnection();
156
157 //post request
158 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
159 out.write(requestBarr,0,requestBarr.length);
160 out.flush();
161
162 // read result from
163 InputStream in = conn.getInputStream();
164 ObjectInputStream ois = new ObjectInputStream(in);
165 result = (Collection) ois.readObject();
166
167 // cleanup
168 ois.close();
169 out.close();
170 conn.disconnect();
171 }
172 catch (Throwable t)
173 {
174 throw new PersistenceBrokerException(t);
175 }
176 return result;
177 }
178
179
180 /**
181 * Add a reader lock entry for transaction tx on object obj
182 * to the persistent storage.
183 */
184 public boolean addReader(TransactionImpl tx, Object obj)
185 {
186 try
187 {
188 LockEntry lock = new LockEntry(new Identity(obj,getBroker()).toString(),
189 tx.getGUID(),
190 System.currentTimeMillis(),
191 LockStrategyFactory.getIsolationLevel(obj),
192 LockEntry.LOCK_READ);
193 addReaderRemote(lock);
194 return true;
195 }
196 catch (Throwable t)
197 {
198 log.error("Cannot store LockEntry for object " + obj + " in transaction " + tx, t);
199 return false;
200 }
201 }
202
203 private void addReaderRemote(LockEntry lock) throws IOException, ClassNotFoundException
204 {
205 byte selector = (byte) 'a';
206 byte[] requestBarr = buildRequestArray(lock,selector);
207
208 HttpURLConnection conn = getHttpUrlConnection();
209
210 //post request
211 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
212 out.write(requestBarr,0,requestBarr.length);
213 out.flush();
214
215 // read result from
216 InputStream in = conn.getInputStream();
217 ObjectInputStream ois = new ObjectInputStream(in);
218 Boolean result = (Boolean) ois.readObject();
219
220 // cleanup
221 ois.close();
222 out.close();
223 conn.disconnect();
224 if (! result.booleanValue())
225 {
226 throw new PersistenceBrokerException("could not add reader!");
227 }
228 }
229
230 public byte[] serialize(Object obj) throws IOException
231 {
232 ByteArrayOutputStream bao = new ByteArrayOutputStream();
233 ObjectOutputStream oos = new ObjectOutputStream(bao);
234 oos.writeObject(obj);
235 oos.close();
236 bao.close();
237 byte[] result = bao.toByteArray();
238 return result;
239 }
240
241 /**
242 * remove a reader lock entry for transaction tx on object obj
243 * from the persistent storage.
244 */
245 public void removeReader(TransactionImpl tx, Object obj)
246 {
247 try
248 {
249 LockEntry lock = new LockEntry(new Identity(obj,getBroker()).toString(), tx.getGUID());
250 removeReaderRemote(lock);
251 }
252 catch (Throwable t)
253 {
254 log.error("Cannot remove LockEntry for object " + obj + " in transaction " + tx);
255 }
256 }
257
258 private void removeReaderRemote(LockEntry lock) throws IOException, ClassNotFoundException
259 {
260 byte selector = (byte) 'e';
261 byte[] requestBarr = buildRequestArray(lock,selector);
262
263 HttpURLConnection conn = getHttpUrlConnection();
264
265 //post request
266 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
267 out.write(requestBarr,0,requestBarr.length);
268 out.flush();
269
270 // read result from
271 InputStream in = conn.getInputStream();
272 ObjectInputStream ois = new ObjectInputStream(in);
273 Boolean result = (Boolean) ois.readObject();
274
275 // cleanup
276 ois.close();
277 out.close();
278 conn.disconnect();
279 if (! result.booleanValue())
280 {
281 throw new PersistenceBrokerException("could not remove reader!");
282 }
283
284 }
285
286 /**
287 * remove a writer lock entry for transaction tx on object obj
288 * from the persistent storage.
289 */
290 public void removeWriter(LockEntry writer)
291 {
292 try
293 {
294 removeWriterRemote(writer);
295 }
296 catch (Throwable t)
297 {
298 log.error("Cannot remove LockEntry", t);
299 }
300 }
301
302 private void removeWriterRemote(LockEntry lock) throws IOException, ClassNotFoundException
303 {
304 byte selector = (byte) 'm';
305 byte[] requestBarr = buildRequestArray(lock,selector);
306
307 HttpURLConnection conn = getHttpUrlConnection();
308
309 //post request
310 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
311 out.write(requestBarr,0,requestBarr.length);
312 out.flush();
313
314 // read result from
315 InputStream in = conn.getInputStream();
316 ObjectInputStream ois = new ObjectInputStream(in);
317 Boolean result = (Boolean) ois.readObject();
318
319 // cleanup
320 ois.close();
321 out.close();
322 conn.disconnect();
323 if (! result.booleanValue())
324 {
325 throw new PersistenceBrokerException("could not remove writer!");
326 }
327
328 }
329
330 /**
331 * upgrade a reader lock entry for transaction tx on object obj
332 * and write it to the persistent storage.
333 */
334 public boolean upgradeLock(LockEntry reader)
335 {
336 try
337 {
338 upgradeLockRemote(reader);
339 reader.setLockType(LockEntry.LOCK_WRITE);
340 return true;
341 }
342 catch (Throwable t)
343 {
344 log.error("Cannot upgrade LockEntry " + reader, t);
345 return false;
346 }
347 }
348
349 private void upgradeLockRemote(LockEntry lock) throws IOException, ClassNotFoundException
350 {
351 byte selector = (byte) 'u';
352 byte[] requestBarr = buildRequestArray(lock,selector);
353
354 HttpURLConnection conn = getHttpUrlConnection();
355
356 //post request
357 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
358 out.write(requestBarr,0,requestBarr.length);
359 out.flush();
360
361 // read result from
362 InputStream in = conn.getInputStream();
363 ObjectInputStream ois = new ObjectInputStream(in);
364 Boolean result = (Boolean) ois.readObject();
365
366 // cleanup
367 ois.close();
368 out.close();
369 conn.disconnect();
370 if (! result.booleanValue())
371 {
372 throw new PersistenceBrokerException("could not remove writer!");
373 }
374
375 }
376
377 /**
378 * generate a writer lock entry for transaction tx on object obj
379 * and write it to the persistent storage.
380 */
381 public boolean setWriter(TransactionImpl tx, Object obj)
382 {
383 try
384 {
385 LockEntry lock = new LockEntry(new Identity(obj,getBroker()).toString(),
386 tx.getGUID(),
387 System.currentTimeMillis(),
388 LockStrategyFactory.getIsolationLevel(obj),
389 LockEntry.LOCK_WRITE);
390
391 setWriterRemote(lock);
392 return true;
393 }
394 catch (Throwable t)
395 {
396 log.error("Cannot set LockEntry for object " + obj + " in transaction " + tx);
397 return false;
398 }
399 }
400
401 private void setWriterRemote(LockEntry lock) throws IOException, ClassNotFoundException
402 {
403 byte selector = (byte) 's';
404 byte[] requestBarr = buildRequestArray(lock,selector);
405
406 HttpURLConnection conn = getHttpUrlConnection();
407
408 //post request
409 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
410 out.write(requestBarr,0,requestBarr.length);
411 out.flush();
412
413 // read result from
414 InputStream in = conn.getInputStream();
415 ObjectInputStream ois = new ObjectInputStream(in);
416 Boolean result = (Boolean) ois.readObject();
417
418 // cleanup
419 ois.close();
420 out.close();
421 conn.disconnect();
422 if (! result.booleanValue())
423 {
424 throw new PersistenceBrokerException("could not set writer!");
425 }
426
427 }
428
429 /**
430 * check if there is a reader lock entry for transaction tx on object obj
431 * in the persistent storage.
432 */
433 public boolean hasReadLock(TransactionImpl tx, Object obj)
434 {
435 try
436 {
437 LockEntry lock = new LockEntry(new Identity(obj,getBroker()).toString(), tx.getGUID());
438 boolean result = hasReadLockRemote(lock);
439 return result;
440 }
441 catch (Throwable t)
442 {
443 log.error("Cannot check read lock for object " + obj + " in transaction " + tx, t);
444 return false;
445 }
446 }
447
448 private boolean hasReadLockRemote(LockEntry lock) throws IOException, ClassNotFoundException
449 {
450 byte selector = (byte) 'h';
451 byte[] requestBarr = buildRequestArray(lock,selector);
452
453 HttpURLConnection conn = getHttpUrlConnection();
454
455 //post request
456 BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());
457 out.write(requestBarr,0,requestBarr.length);
458 out.flush();
459
460 // read result from
461 InputStream in = conn.getInputStream();
462 ObjectInputStream ois = new ObjectInputStream(in);
463 Boolean result = (Boolean) ois.readObject();
464
465 // cleanup
466 ois.close();
467 out.close();
468 conn.disconnect();
469 return result.booleanValue();
470 }
471
472
473
474
475 /**
476 * @see org.apache.ojb.broker.util.configuration.Configurable#configure(org.apache.ojb.broker.util.configuration.Configuration)
477 */
478 public void configure(Configuration pConfig) throws ConfigurationException
479 {
480 String url = pConfig.getString("LockServletUrl","http://127.0.0.1:8080/ojb-lockserver");
481 try
482 {
483 lockservlet = new URL(url);
484 }
485 catch (MalformedURLException e)
486 {
487 throw new ConfigurationException("Invalid LockServlet Url was specified: " + url, e);
488 }
489
490 }
491
492 }