View Javadoc

1   package net.sourceforge.domian.repository;
2   
3   
4   import java.util.concurrent.Callable;
5   import java.util.concurrent.ExecutionException;
6   import java.util.concurrent.Future;
7   import java.util.concurrent.FutureTask;
8   import static java.util.concurrent.TimeUnit.MILLISECONDS;
9   import java.util.concurrent.TimeoutException;
10  
11  import static org.apache.commons.lang.StringUtils.uncapitalize;
12  
13  import net.sourceforge.domian.entity.Entity;
14  import static net.sourceforge.domian.util.InstrumentationUtils.buildMessageWithStackTrace;
15  import static net.sourceforge.domian.util.InstrumentationUtils.buildThreadNumberAndMessage;
16  import net.sourceforge.domian.util.concurrent.locks.Synchronizer;
17  import static net.sourceforge.domian.util.concurrent.locks.Synchronizer.MODE.CONCURRENT;
18  import static net.sourceforge.domian.util.concurrent.locks.Synchronizer.MODE.EXCLUSIVE;
19  
20  
21  // TODO: consider merging into HibernateRepository or move to common helper class...
22  // TODO: ...or maybe just remove this class and start all over again when needed (go with AbstractSynchronizedObject)
23  @Deprecated
24  abstract class AbstractHibernateRepository<T extends Entity> extends AbstractDomianCoreRepository<T> {
25  
26      private static final int ALL_STACKTRACE_LINES = 60;
27  
28      /**
29       * When using the <code>*WithRetry</code> methods,
30       * this value defines the maximum number of times an operation will be retried.
31       * <p/>
32       * The default value is 2.
33       */
34      private Integer maxNumberOfRetries = 1;
35  
36      /**
37       * When using the <code>*WithRetry</code> methods,
38       * this value defines the timeout for all retried operations.
39       * <p/>
40       * The default value is 500.
41       */
42      private Integer retryTimeoutInMilliseconds = 6000;
43  
44      public Integer getMaxNumberOfRetries() {
45          return maxNumberOfRetries;
46      }
47  
48      public void setMaxNumberOfRetries(final Integer maxNumberOfRetries) {
49          this.maxNumberOfRetries = maxNumberOfRetries;
50      }
51  
52      public Integer getRetryTimeoutInMilliseconds() {
53          return retryTimeoutInMilliseconds;
54      }
55  
56      public void setRetryTimeoutInMilliseconds(final Integer retryTimeoutInMilliseconds) {
57          this.retryTimeoutInMilliseconds = retryTimeoutInMilliseconds;
58      }
59  
60      ///////////////////////////////////////////////
61      // Synchronizer convenience methods
62      // TODO v0.5: move to some common helper class
63      ///////////////////////////////////////////////
64  
65      /** Added for completeness. */
66      protected void run(final Runnable runnable) {
67          runnable.run();
68      }
69  
70      /** Added for completeness. */
71      protected void call(final Callable<T> callable) throws Exception {
72          callable.call();
73      }
74  
75      /**
76       * Convenience method for running a {@link Runnable} in a concurrent manner.
77       *
78       * @see net.sourceforge.domian.util.concurrent.locks.Synchronizer
79       */
80      protected void runConcurrently(final Runnable runnable) {
81          this.synchronizer.runConcurrently(runnable);
82      }
83  
84      /**
85       * Convenience method for running a {@link java.util.concurrent.Callable} in a concurrent manner.
86       *
87       * @see net.sourceforge.domian.util.concurrent.locks.Synchronizer
88       */
89      protected <T> T callConcurrently(final Callable<T> callable) {
90          return this.synchronizer.callConcurrently(callable);
91      }
92  
93      /**
94       * Convenience method for running a {@link java.util.concurrent.Callable} in an exclusively manner.
95       *
96       * @see net.sourceforge.domian.util.concurrent.locks.Synchronizer
97       */
98      protected <T> T callExclusively(final Callable<T> callable) {
99          return this.synchronizer.callExclusively(callable);
100     }
101 
102     /**
103      * Convenience method for running a {@link java.util.concurrent.Callable} in a concurrent manner.
104      * If an exception is thrown, the {@link java.util.concurrent.Callable} will be immediately <i>retried</i>.
105      * The nature of the retries are further defined by the <code>maxNumberOfRetries</code> and
106      * <code>retryTimeoutInMilliseconds</code> member values.
107      */
108     protected <T> T callConcurrentlyWithRetry(final Callable<T> callable) {
109         try {
110             return callConcurrently(callable);
111 
112         } catch (Exception e) {
113             return retry(callable, e, CONCURRENT);
114         }
115     }
116 
117     /**
118      * Convenience method for running a {@link java.util.concurrent.Callable} in an exclusively manner.
119      * If an exception is thrown, the {@link java.util.concurrent.Callable} will be immediately queued for <i>retrial</i>.
120      * The nature of the retries are further defined by the <code>maxNumberOfRetries</code> and
121      * <code>retryTimeoutInMilliseconds</code> member values.
122      */
123     protected <T> T callExclusivelyWithRetry(final Callable<T> callable) {
124         try {
125             return callExclusively(callable);
126 
127         } catch (Exception e) {
128             return retry(callable, e, EXCLUSIVE);
129         }
130     }
131 
132     protected <T> T callInNewThread(final Callable<T> callable) throws ExecutionException, TimeoutException, InterruptedException {
133         return new FutureTask<T>(callable).get(this.retryTimeoutInMilliseconds, MILLISECONDS);
134     }
135 
136     protected <T> T callConcurrentlyInNewThread(final Callable<T> callable) throws ExecutionException, TimeoutException, InterruptedException {
137         final Future<T> future = new FutureTask<T>(callable);
138         this.synchronizer.runConcurrently((FutureTask) future);
139         return future.get(this.retryTimeoutInMilliseconds, MILLISECONDS);
140     }
141 
142     protected <T> T callExclusivelyInNewThread(final Callable<T> callable) throws ExecutionException, TimeoutException, InterruptedException {
143         final Future<T> future = new FutureTask<T>(callable);
144         this.synchronizer.runExclusively((FutureTask) future);
145         return future.get(this.retryTimeoutInMilliseconds, MILLISECONDS);
146     }
147 
148     /**
149      * Executes the given {@link Runnable} in a fresh and independent thread.
150      * <i>This method does not block the original thread.</i>
151      * The {@link net.sourceforge.domian.util.concurrent.locks.Synchronizer} mode is <i>concurrent</i>.
152      * (An asynchronous version of {@link net.sourceforge.domian.util.concurrent.locks.Synchronizer} in <i>exclusive</i> mode has no meaning,
153      * as it is a "stop-the-world" kind of mode.)
154      */
155     protected void runAsynchronously(final Runnable runnable) {
156         runConcurrently(new FutureTask<T>(runnable, null));
157     }
158 
159     /**
160      * Executes the given {@link java.util.concurrent.Callable} in a fresh thread, with time-out set to <code>retryTimeoutInMilliseconds</code>.
161      * The {@link java.util.concurrent.Callable} will be retried <code>maxNumberOfRetries</code> times.
162      * <p/>
163      * This method will use an uncapitalized version of the given callable's simple class name as method name.
164      */
165     private <T> T retry(final Callable<T> callable, final Exception retryReason, final Synchronizer.MODE synchronizedMode) {
166         return retry(uncapitalize(callable.getClass().getSimpleName()), callable, retryReason, synchronizedMode);
167     }
168 
169     /**
170      * Executes the given {@link java.util.concurrent.Callable} in a fresh thread, with time-out set to <code>retryTimeoutInMilliseconds</code>.
171      * The {@link java.util.concurrent.Callable} will be retried <code>maxNumberOfRetries</code> times.
172      */
173     private <T> T retry(final String methodName, final Callable<T> callable, final Exception reasonForRetry, final Synchronizer.MODE synchronizedMode) {
174         if (log.isDebugEnabled()) { log.debug(buildThreadNumberAndMessage("loggelinje nummer 2")); }
175         log.warn(buildThreadNumberAndMessage("XStream failure while working with persistent data: " + buildMessageWithStackTrace(reasonForRetry, reasonForRetry.toString(), 0, 0)));
176         if (log.isDebugEnabled()) {
177             log.debug(buildThreadNumberAndMessage("XStream failure while working with persistent data: " + buildMessageWithStackTrace(reasonForRetry, reasonForRetry.toString(), ALL_STACKTRACE_LINES, 0)));
178         }
179         log.warn(buildThreadNumberAndMessage(this.getClass().getName() + "." + methodName + "() will be retried [max " + this.maxNumberOfRetries + " times, with time-out set to " + this.retryTimeoutInMilliseconds + " ms]"));
180         int numberOfRetries = 0;
181         while (numberOfRetries <= this.maxNumberOfRetries) {
182             if (log.isWarnEnabled()) {
183                 log.warn(buildThreadNumberAndMessage(this.getClass().getName() + "." + methodName + "() retry #" + (numberOfRetries + 1)));
184             }
185             try {
186                 switch (synchronizedMode) {
187                     case CONCURRENT:
188                         return callConcurrentlyInNewThread(callable);
189                     case EXCLUSIVE:
190                         return callExclusivelyInNewThread(callable);
191                     default:
192                         throw new IllegalStateException(synchronizedMode + " is not a valid net.sourceforge.domian.util.Synchronizer mode");
193                 }
194 
195             } catch (Exception e) {
196                 ++numberOfRetries;
197                 if (log.isDebugEnabled()) { log.debug(buildThreadNumberAndMessage("loggelinje nummer 4")); }
198                 log.warn(buildThreadNumberAndMessage("XStream failure while working with persistent data: " + buildMessageWithStackTrace(e, e.toString(), 0, 0)));
199                 if (log.isDebugEnabled()) {
200                     log.debug(buildThreadNumberAndMessage("XStream failure while working with persistent data: " + buildMessageWithStackTrace(e, e.toString(), ALL_STACKTRACE_LINES, 0)));
201                 }
202 
203                 if (numberOfRetries >= this.maxNumberOfRetries) {
204                     throw new RepositoryException(this.getClass().getName() + "." + methodName + "() failed! Max number of retries [" + this.maxNumberOfRetries + "] reached, aborting operation!");
205                 }
206             }
207         }
208         throw new RepositoryException(this.getClass().getName() + "." + methodName + "() failed", reasonForRetry);
209     }
210 }