1 /**
2 * - Digitalis Internal Framework v2.0 - (C) 2007, Digitalis Informatica. Distribuicao e Gestao de Informatica, Lda.
3 * Estrada de Paco de Arcos num.9 - Piso -1 2780-666 Paco de Arcos Telefone: (351) 21 4408990 Fax: (351) 21 4408999
4 * http://www.digitalis.pt
5 */
6 package pt.digitalis.dif.controller;
7
8 import pt.digitalis.dif.controller.interfaces.IChAL;
9 import pt.digitalis.dif.controller.interfaces.IDIFDispatcher;
10 import pt.digitalis.dif.controller.interfaces.IDIFRequest;
11 import pt.digitalis.dif.controller.interfaces.IDIFResponse;
12 import pt.digitalis.dif.controller.interfaces.IDispatcherErrorHandler;
13 import pt.digitalis.dif.controller.objects.ClientDescriptor;
14 import pt.digitalis.dif.controller.objects.RESTAction;
15 import pt.digitalis.dif.dem.annotations.controller.Channel;
16 import pt.digitalis.dif.dem.managers.IMessageManager;
17 import pt.digitalis.dif.exception.controller.BusinessFlowException;
18 import pt.digitalis.dif.exception.controller.ControllerException;
19 import pt.digitalis.dif.ioc.DIFIoCRegistry;
20
21 import com.newrelic.api.agent.Trace;
22
23 /**
24 * Base implementation for all ChALs The API exposed to the Listener entities is the <code>serve()</code> method. All
25 * the communication between AbstractChAL and Listener is done through this API.
26 *
27 * @param <RequestType>
28 * type original request type
29 * @param <ResponseType>
30 * the original response type
31 * @author Rodrigo Gonçalves <a href="mailto:rgoncalves@digitalis.pt">rgoncalves@digitalis.pt</a>
32 * @author Pedro Viegas <a href="mailto:pviegas@digitalis.pt">pviegas@digitalis.pt</a>
33 * @created 2007/03/27
34 */
35 abstract public class AbstractChAL<RequestType, ResponseType> implements IChAL<RequestType, ResponseType> {
36
37 /** The channel ID */
38 private String channelID = null;
39
40 /** The message manager. */
41 protected IMessageManager messageManager = DIFIoCRegistry.getRegistry().getImplementation(IMessageManager.class);
42
43 /**
44 * Get the id of the channel associated to the ChAL. If the id is unset the method reads the channel id from the
45 * annotation.
46 *
47 * @return the channel ID read from the {@link Channel} annotation
48 */
49 public String getChannelID()
50 {
51 if (channelID == null)
52 channelID = this.getClass().getAnnotation(Channel.class).value();
53
54 return channelID;
55 }
56
57 /**
58 * Creates a client descriptor object identifying the client agent who issued the request
59 *
60 * @param originalRequest
61 * the original request object
62 * @return the client descriptor for the current request
63 * @throws ControllerException
64 * when any runtime exception is thrown
65 */
66 abstract protected ClientDescriptor getClientDescriptor(RequestType originalRequest) throws ControllerException;
67
68 /**
69 * Inspector of the dispatcher assigned to this channel.
70 *
71 * @return theDispatcher attribute
72 */
73 protected IDIFDispatcher getDispatcher()
74 {
75 return DIFIoCRegistry.getRegistry().getImplementation(IDIFDispatcher.class, getChannelID());
76 }
77
78 /**
79 * Inspector of the dispatcher assigned to this channel.
80 *
81 * @return theDispatcher attribute
82 */
83 protected IDispatcherErrorHandler getErrorHandler()
84 {
85 return DIFIoCRegistry.getRegistry().getImplementation(IDispatcherErrorHandler.class, getChannelID());
86 }
87
88 /**
89 * @see pt.digitalis.dif.controller.interfaces.IChAL#serve(java.lang.Object, java.lang.Object,
90 * pt.digitalis.dif.controller.objects.RESTAction)
91 * @param originalRequest
92 * the original request object
93 * @param finalResponse
94 * the final response object
95 * @param restAction
96 * the REST action, if specified
97 * @return the processed DIFResponse
98 */
99 @Trace(metricName = "DIF:ChAL:Serve", dispatcher = true)
100 public IDIFResponse serve(RequestType originalRequest, ResponseType finalResponse, RESTAction restAction)
101 {
102
103 IDIFResponse difResponse = null;
104 IDIFRequest difRequest = null;
105
106 try
107 {
108 difRequest = translateRequest(originalRequest);
109 difRequest.setRestAction(restAction);
110
111 // Initializes the client descriptor if ins't filled. The translateRequest is responsible for filling it.
112 if (difRequest.getClient() == null)
113 difRequest.setClient(getClientDescriptor(originalRequest));
114
115 if (validateRequest(originalRequest))
116 {
117
118 difResponse = getDispatcher().dispatch(difRequest);
119
120 // Fail-over. Should never return null.
121 if (difResponse == null)
122 difResponse = getErrorHandler().getDefaultErrorResponse(difRequest, null);
123
124 }
125 else
126 difResponse = getErrorHandler().getDefaultErrorResponse(difRequest, null);
127
128 }
129 catch (BusinessFlowException exception)
130 {
131 difResponse = getErrorHandler().processException(difRequest, exception);
132 }
133 catch (RuntimeException exception)
134 {
135 difResponse = getErrorHandler().processException(difRequest, exception);
136 }
137 catch (ControllerException exception)
138 {
139 difResponse = getErrorHandler().processException(difRequest, exception);
140 }
141
142 this.publish(difResponse, originalRequest, finalResponse);
143
144 return difResponse;
145 }
146
147 /**
148 * Validates the original request. It can be used to check if a particular request is valid for the channel. It may
149 * also perform other validations, as the request parameters integrity.
150 *
151 * @param originalRequest
152 * The original request received from the client.
153 * @return T case the request is well formed, F otherwise
154 * @throws ControllerException
155 * when any runtime exception is thrown
156 */
157 abstract protected boolean validateRequest(RequestType originalRequest) throws ControllerException;
158 }