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    }