1 package org
.argeo
.slc
.detached
;
3 import java
.io
.PrintWriter
;
4 import java
.io
.StringWriter
;
6 import java
.util
.Vector
;
8 import org
.apache
.commons
.io
.IOUtils
;
9 import org
.apache
.commons
.logging
.Log
;
10 import org
.apache
.commons
.logging
.LogFactory
;
11 import org
.argeo
.slc
.detached
.admin
.CloseSession
;
12 import org
.argeo
.slc
.detached
.admin
.OpenSession
;
13 import org
.osgi
.framework
.BundleContext
;
14 import org
.osgi
.framework
.ServiceReference
;
15 import org
.springframework
.context
.ApplicationContext
;
16 import org
.springframework
.osgi
.context
.BundleContextAware
;
18 /** Default implementation of a detached server. */
19 public class DetachedExecutionServerImpl
implements DetachedExecutionServer
,
21 private final static Log log
= LogFactory
22 .getLog(DetachedExecutionServerImpl
.class);
24 private final DetachedContextImpl detachedContext
;
25 private final List sessions
;
27 private int skipCount
= 1;// start skipCount at 1 since the first step is
28 // always an open session
30 private BundleContext bundleContext
;
32 public DetachedExecutionServerImpl() {
33 detachedContext
= new DetachedContextImpl();
34 sessions
= new Vector();
37 public synchronized DetachedAnswer
executeRequest(DetachedRequest request
) {
38 log
.info("Received request " + request
);
40 DetachedAnswer answer
= null;
43 ServiceReference
[] refs
= bundleContext
.getAllServiceReferences(
44 ApplicationContext
.class.getName(), null);
46 for (int i
= 0; i
< refs
.length
; i
++) {
47 ApplicationContext appContext
= (ApplicationContext
) bundleContext
50 obj
= appContext
.getBean(request
.getRef());
51 } catch (Exception e
) {
53 if (log
.isTraceEnabled())
54 log
.trace("Could not find ref " + request
.getRef(), e
);
62 throw new DetachedException("Could not find action with ref "
66 if (obj
instanceof DetachedStep
) {
67 answer
= processStep((DetachedStep
) obj
, request
);
69 } else if (obj
instanceof DetachedAdminCommand
) {
70 answer
= processAdminCommand((DetachedAdminCommand
) obj
,
75 throw new DetachedException("Unknown action type "
76 + obj
.getClass() + " for action with ref "
79 } catch (Exception e
) {
80 answer
= new DetachedAnswer(request
);
81 answer
.setStatus(DetachedAnswer
.ERROR
);
82 StringWriter writer
= new StringWriter();
83 e
.printStackTrace(new PrintWriter(writer
));
84 answer
.setLog(writer
.toString());
85 IOUtils
.closeQuietly(writer
);
88 // Case where current session is unexpectly null
89 if (getCurrentSession() == null) {
91 .error("CURRENT SESSION IS NULL."
92 + " Detached status is inconsistent dumping sessions history:");
93 log
.error(dumpSessionsHistory(request
, answer
));
95 answer
.setStatus(DetachedAnswer
.ERROR
);
97 .addToLog("CURRENT SESSION IS NULL."
98 + " Detached status is inconsistent, see detached log for more details.");
101 throw new DetachedException(
102 "Answer is null. Cannot return it. See log for more details.");
107 getCurrentSession().getRequests().add(request
);
108 getCurrentSession().getAnswers().add(answer
);
109 log
.info("Sent answer " + answer
);
113 protected synchronized DetachedAnswer
processStep(DetachedStep obj
,
114 DetachedRequest request
) {
115 DetachedAnswer answer
;
116 if (getCurrentSession() == null)
117 throw new DetachedException("No open session.");
119 StringBuffer skippedLog
= new StringBuffer();
120 boolean execute
= true;
121 if (getPreviousSession() != null && !getPreviousSession().isClosed()) {
122 if (getCurrentSession().getDoItAgainPolicy().equals(
123 DetachedSession
.SKIP_UNTIL_ERROR
)) {
124 // Skip execution of already successful steps
125 if (getPreviousSession().getAnswers().size() > skipCount
) {
126 DetachedAnswer previousAnswer
= (DetachedAnswer
) getPreviousSession()
127 .getAnswers().get(skipCount
);
128 DetachedRequest previousRequest
= (DetachedRequest
) getPreviousSession()
129 .getRequests().get(skipCount
);
131 if (!previousRequest
.getPath().equals(request
.getPath())) {
132 String msg
= "New request is not consistent with previous path. previousPath="
133 + previousRequest
.getPath()
135 + request
.getPath() + "\n";
136 skippedLog
.append(msg
);
140 if (previousAnswer
.getStatus() != DetachedAnswer
.ERROR
) {
142 String msg
= "Skipped path " + request
.getPath()
143 + " (skipCount=" + skipCount
+ ")";
144 skippedLog
.append(msg
);
151 + " was previously in error, executing it again."
152 + " (skipCount=" + skipCount
153 + "). Reset skip count to 1");
157 // went further as skip count, doing nothing.
163 DetachedStep step
= (DetachedStep
) obj
;
164 // Actually execute the step
165 answer
= step
.execute(detachedContext
, request
);
167 answer
= new DetachedAnswer(request
);
168 answer
.setStatus(DetachedAnswer
.SKIPPED
);
169 answer
.setLog(skippedLog
.toString());
174 protected synchronized DetachedAnswer
processAdminCommand(
175 DetachedAdminCommand obj
, DetachedRequest request
) {
176 DetachedAnswer answer
;
177 if (obj
instanceof OpenSession
) {
178 if (getCurrentSession() != null) {
179 // TODO: better understand why there is sometimes two open
181 log
.warn("There is already an open session #"
182 + getCurrentSession().getUuid() + ". Closing it...");
183 DetachedAnswer answerT
= new DetachedAnswer(
186 + getCurrentSession().getUuid()
187 + " forcibly closed. THIS ANSWER WAS NOT SENT BACK.");
188 answerT
.setStatus(DetachedAnswer
.CLOSED_SESSION
);
189 getCurrentSession().getAnswers().add(answerT
);
191 sessions
.add(((OpenSession
) obj
).execute(request
, bundleContext
));
192 answer
= new DetachedAnswer(request
, "Session #"
193 + getCurrentSession().getUuid() + " open.");
194 } else if (obj
instanceof CloseSession
) {
195 if (getCurrentSession() == null)
196 throw new DetachedException("There is no open session to close");
197 answer
= new DetachedAnswer(request
, "Session #"
198 + getCurrentSession().getUuid() + " closed.");
199 answer
.setStatus(DetachedAnswer
.CLOSED_SESSION
);
207 * Returns the current session based on the list of previous sessions.
209 * @return the current session or null if there is no session yet defined or
210 * if the last registered session is null or in error.
212 protected synchronized final DetachedSession
getCurrentSession() {
213 if (sessions
.size() == 0) {
216 DetachedSession session
= (DetachedSession
) sessions
.get(sessions
218 List answers
= session
.getAnswers();
219 if (answers
.size() > 0) {
220 DetachedAnswer lastAnswer
= (DetachedAnswer
) answers
221 .get(answers
.size() - 1);
222 if (lastAnswer
.getStatus() == DetachedAnswer
.ERROR
223 || lastAnswer
.getStatus() == DetachedAnswer
.CLOSED_SESSION
)
230 protected synchronized String
dumpSessionsHistory(
231 DetachedRequest requestCurrent
, DetachedAnswer answerCurrent
) {
232 StringBuffer buf
= new StringBuffer("## SESSIONS HISTORY DUMP\n");
233 buf
.append("# CURRENT\n");
234 buf
.append("Current session: ").append(getCurrentSession())
236 buf
.append("Current request: ").append(requestCurrent
).append('\n');
237 buf
.append("Current answer: ").append(answerCurrent
).append('\n');
238 buf
.append("Skip count: ").append(skipCount
).append('\n');
240 buf
.append("# SESSIONS\n");
241 for (int i
= 0; i
< sessions
.size(); i
++) {
242 DetachedSession session
= (DetachedSession
) sessions
.get(i
);
243 buf
.append(i
).append(". ").append(session
).append('\n');
244 List requests
= session
.getRequests();
245 List answers
= session
.getAnswers();
246 for (int j
= 0; j
< requests
.size(); j
++) {
247 DetachedRequest request
= (DetachedRequest
) requests
.get(j
);
248 buf
.append('\t').append(j
).append(". ").append(request
).append(
250 if (answers
.size() > j
) {
251 DetachedAnswer answer
= (DetachedAnswer
) answers
.get(j
);
252 buf
.append('\t').append(j
).append(". ").append(answer
)
258 buf
.append("# DETACHED CONTEXT\n");
259 buf
.append(detachedContext
).append('\n');
261 return buf
.toString();
264 protected synchronized final DetachedSession
getPreviousSession() {
265 if (sessions
.size() < 2)
268 return (DetachedSession
) sessions
.get(sessions
.size() - 2);
271 public void setBundleContext(BundleContext bundleContext
) {
272 this.bundleContext
= bundleContext
;