View Javadoc

1   /*
2    * Copyright (c) 2005, The K-Wf Grid Consortium
3    * Fraunhofer Institute for Computer Architecture and Software Technology
4    * See http://www.kwfgrid.eu and http://www.first.fraunhofer.de for more details.
5    */
6   package net.kwfgrid.gwui.servlets;
7   
8   import javax.servlet.http.HttpServlet;
9   import javax.servlet.http.HttpServletRequest;
10  import javax.servlet.http.HttpServletResponse;
11  import javax.servlet.http.HttpSession;
12  import javax.servlet.ServletException;
13  import javax.servlet.ServletContext;
14  import javax.servlet.RequestDispatcher;
15  import java.io.*;
16  import java.net.URL;
17  import java.net.MalformedURLException;
18  import java.net.URLDecoder;
19  import java.util.Map;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.Properties;
23  import java.util.List;
24  import java.util.LinkedList;
25  import java.util.Enumeration;
26  import java.util.StringTokenizer;
27  import java.rmi.RemoteException;
28  
29  import net.kwfgrid.gworkflowdl.protocol.IllegalModificationException;
30  import net.kwfgrid.gworkflowdl.protocol.IncompatibleVersionsException;
31  import net.kwfgrid.gworkflowdl.protocol.client.ClientWorkflow;
32  import net.kwfgrid.gworkflowdl.structure.*;
33  import net.kwfgrid.gwui.workflow.XMLUtilities;
34  
35  import org.apache.log4j.Logger;
36  
37  /***
38     Servlet to allow the user to select between different forms for data input.
39     This servlet MUST be deployed in the same webapp as the data-servlets and must be addressable
40     at path "/FormSelectionServlet".
41   */
42  public class FormSelectionServlet extends HttpServlet implements ServletConstants {
43      private static final Logger logger = Logger.getLogger(FormSelectionServlet.class);
44  
45      /*** The key for the "servlet" parameter. */
46      public static final String KEY_SERVLET = "servlet";
47  
48      /*** The key for the "form-selection-template-url" property. */
49      public static final String KEY_FORM_SELECTION_TEMPLATE_URL = "form-selection-template-url";
50      /*** The key for the "generic-form-url" property */
51      public static final String KEY_GENERIC_FORM_URL = "generic-form-url";
52      /*** The key for the "generic-form-width" property */
53      public static final String KEY_GENERIC_FORM_WIDTH = "generic-form-width";
54      /*** The key for the "generic-form-height" property */
55      public static final String KEY_GENERIC_FORM_HEIGHT = "generic-form-height";
56      /*** The key for the "control-token-form-url" property */
57      public static final String KEY_CONTROL_TOKEN_FORM_URL = "control-token-form-url";
58      /*** The key for the "control-token-form-width" property */
59      public static final String KEY_CONTROL_TOKEN_FORM_WIDTH = "control-token-form-width";
60      /*** The key for the "control-token-form-height" property */
61      public static final String KEY_CONTROL_TOKEN_FORM_HEIGHT = "control-token-form-height";
62      /*** The key for the "form-selection-template-width" property */
63      public static final String KEY_FORM_SELECTION_TEMPLATE_WIDTH = "form-selection-template-width";
64      /*** The key for the "form-selection-template-width" property */
65      public static final String KEY_FORM_SELECTION_TEMPLATE_HEIGHT = "form-selection-template-height";
66  
67      public static final String PLACEHOLDER_ADDITIONAL_PARAMETERS = "//$ADDITIONAL_PARAMETERS";
68      public static final String PLACEHOLDER_FORM_URLS = "//$FORM_ARRAY";
69      public static final String PLACEHOLDER_SERVLET_NAMES = "//$SERVLET_ARRAY";
70      public static final String PLACEHOLDER_FORM_WIDTHS = "//$WIDTH_ARRAY";
71      public static final String PLACEHOLDER_FORM_HEIGHTS = "//$HEIGHT_ARRAY";
72      public static final String PLACEHOLDER_FORMSELECTIONSERVLET_URLS = "//$SELECTION_SERVLET_ARRAY";
73      public static final String PLACEHOLDER_GENERIC_SERVLET = "//$GENERIC_SERVLET";
74      public static final String PLACEHOLDER_GENERIC_FORM = "//$GENERIC_FORM_URL";
75      public static final String PLACEHOLDER_GENERIC_FORM_WIDTH = "//$GENERIC_FORM_WIDTH";
76      public static final String PLACEHOLDER_GENERIC_FORM_HEIGHT = "//$GENERIC_FORM_HEIGHT";
77      public static final String PLACEHOLDER_GENERIC_FORMSELECTIONSERVLET = "//$GENERIC_SELECTION_SERVLET";
78      public static final String PLACEHOLDER_TEMPLATE_WIDTH = "//$TEMPLATE_WIDTH";
79      public static final String PLACEHOLDER_TEMPLATE_HEIGHT = "//$TEMPLATE_HEIGHT";
80  
81      private static Properties PROPERTIES = new Properties();
82  
83      static {
84  	try {
85  	    PROPERTIES.load(FormSelectionServlet.class.getResourceAsStream("/dataservletbase.properties"));
86  
87  	    if (PROPERTIES.getProperty(KEY_SERVLET_BASE_URL) == null)
88  		throw new IOException("No servlet-base-url property defined.");
89  	    if (PROPERTIES.getProperty(KEY_GENERIC_FORM_URL) == null)
90  		throw new IOException("No generic-form-url property defined.");
91  	    if (PROPERTIES.getProperty(KEY_GENERIC_FORM_WIDTH) == null)
92  		throw new IOException("No generic-form-width property defined.");
93   	    if (PROPERTIES.getProperty(KEY_GENERIC_FORM_HEIGHT) == null)
94  		throw new IOException("No generic-form-height property defined.");
95  	    if (PROPERTIES.getProperty(KEY_CONTROL_TOKEN_FORM_URL) == null)
96  		throw new IOException("No control-token-form-url property defined.");
97  	    if (PROPERTIES.getProperty(KEY_CONTROL_TOKEN_FORM_WIDTH) == null)
98  		throw new IOException("No control-token-form-width property defined.");
99   	    if (PROPERTIES.getProperty(KEY_CONTROL_TOKEN_FORM_HEIGHT) == null)
100 		throw new IOException("No control-token-form-height property defined.");
101 	    if (PROPERTIES.getProperty(KEY_FORM_SELECTION_TEMPLATE_URL) == null)
102 		throw new IOException("No form-selection-template-url property defined.");
103 	    if (PROPERTIES.getProperty(KEY_FORM_SELECTION_TEMPLATE_HEIGHT) == null)
104 		throw new IOException("No form-selection-template-height property defined.");
105 	    if (PROPERTIES.getProperty(KEY_FORM_SELECTION_TEMPLATE_WIDTH) == null)
106 		throw new IOException("No form-selection-template-width property defined.");
107 	} catch (Exception x) {
108 	    logger.fatal("Could not load properties.", x);
109 	}	
110     }
111 
112     protected String getProperty(String key) {
113 	return PROPERTIES.getProperty(key);
114     }
115 
116     protected void doPost(HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
117         doAll( request, response );
118     }
119 
120     protected void doGet(HttpServletRequest request,  HttpServletResponse response ) throws ServletException, IOException {
121         doAll( request, response );
122     }
123 
124     private void doAll(HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
125 	HttpSession session = request.getSession(false);
126 	boolean shouldbenew = request.getParameter(KEY_NEWSESSION)!=null;
127 
128 	if (session != null && shouldbenew) {
129 	    logger.info("Got outdated session information. Discarding and starting new session...");
130 	    session.invalidate();
131 	    session = null;
132 	}
133 
134 	ClientWorkflow workflow = null;
135 	String servlet = request.getParameter(KEY_SERVLET);
136 	boolean requestfromuser = servlet != null;
137 
138 	try {
139 	    if (session == null && !requestfromuser) {
140 		String gwesaddress = request.getParameter(KEY_GWESADDRESS);
141 		String workflowid = request.getParameter(KEY_WORKFLOWID);
142 		String command = request.getParameter(KEY_COMMAND);
143 		String placeid = request.getParameter(KEY_PLACEID);
144 		String transitionid = request.getParameter(KEY_TRANSITIONID);
145 		
146 		workflow = (ClientWorkflow)Factory.newWorkflow(workflowid);
147 		workflow.update();
148 		
149 		if (EDIT_COMMAND.equals(command) || 
150 		    CREATE_COMMAND.equals(command)) {
151 		    Place place = workflow.getPlace(placeid);
152 		    if (place == null) 
153 			throw new ServletException("Place with ID "+placeid+" not available.");
154 		    showForPlace(place, createAdditionalParameters(request), null, request, response);
155 		} else if (FIRE_COMMAND.equals(command)) {
156 		    Transition transition = workflow.getTransition(transitionid);
157 		    if (transition == null)
158 			throw new ServletException("Transition with ID "+transitionid+" not available.");
159 		    Edge[] outedges = transition.getOutEdges();
160 		    if (outedges.length < 1)
161 			throw new ServletException("No output places available at transition with ID "+transitionid+".");
162 		    Place place = outedges[0].getPlace();
163 		    showForPlace(place, createAdditionalParameters(request), null, request, response);
164 		} else {
165 		    throw new ServletException("Unknown command: "+command);
166 		}	    
167 	    } else {
168 		if (requestfromuser) {
169 		    ServletContext ctx = getServletContext();
170 		    RequestDispatcher rq = ctx.getRequestDispatcher("/"+servlet);
171 		    logger.info("Forwarding request to "+servlet+".");
172 		    rq.forward(request, response);
173 		} else {
174 		    workflow = (ClientWorkflow)session.getAttribute(KEY_WORKFLOWINSTANCE);
175 		    String transitionid = (String)session.getAttribute(KEY_TRANSITIONID);
176 		    Transition transition = workflow.getTransition(transitionid);	
177 		    int outedgeindex = ((Integer)session.getAttribute(KEY_OUTEDGEINDEX)).intValue();
178 		    Edge[] outedges = transition.getOutEdges();	
179 		    Place place = outedges[outedgeindex].getPlace();
180 		    showForPlace(place, "", getProperty(KEY_SERVLET_BASE_URL), request, response);
181 		}
182 	    }
183 	} catch (UnsupportedEncodingException x) {
184 	    throw new ServletException("Unsupported encoding.", x);
185 	}
186     }
187 
188     private String createAdditionalParameters(HttpServletRequest request) throws UnsupportedEncodingException {
189 	StringBuffer p = new StringBuffer();
190 	Enumeration e = request.getParameterNames();
191 	while (e.hasMoreElements()) {
192 	    String name = (String)e.nextElement();
193 	    String value = ServletUtilities.decode(request.getParameter(name));
194 	    p.append("&").append(name).append("=").append(value);
195 	}
196 	return p.toString();
197     }
198 
199     /***
200        @param place The place.
201        @param js_additionalparameters Additional parameters to be included into the form 
202        (only if this is the first call of FormSelectionServlet during a session, empty string otherwise).
203        @param servlethost The servlethost (plus the path to the webapp) where the servlets must reside 
204        (only if this is a subsequent call during a session, null if it is the first call.)
205        @param request
206        @param response
207      */
208     private void showForPlace(Place place, 
209 			      String js_additionalparameters, 
210 			      String servlethost,
211 			      HttpServletRequest request, 
212 			      HttpServletResponse response) 
213 	throws ServletException, IOException {
214 	List forms = new LinkedList();
215 	String[] formurls = parseStringArray(place.getProperties().get("token.form.urls"));
216 	String[] servleturls = parseStringArray(place.getProperties().get("token.servlet.urls"));
217 	String[][] geometries = parseGeometriesArray(parseStringArray(place.getProperties().get("token.form.geometries")));
218 	String[] formselectionservleturls = new String[servleturls.length];
219 	String[] servlethosts = new String[servleturls.length];
220 	String[] servletnames = new String[servleturls.length];
221 
222 	if (formurls.length != servleturls.length ||
223 	    formurls.length != geometries[0].length ||
224 	    servleturls.length != geometries[0].length) 
225 	    throw new ServletException("Invalid form properties at place "+place.getID());
226 
227 	for (int i=0; i<servleturls.length; i++) {
228 	    if (servleturls[i].equalsIgnoreCase("na")) {
229 		if (servlethost == null) 
230 		    servleturls[i] = getProperty(KEY_SERVLET_BASE_URL)+"DefaultDataServlet";
231 		else
232 		    servleturls[i] = servlethost + "DefaultDataServlet";
233 	    }
234 	    
235 	    servlethosts[i] = servleturls[i].substring(0, servleturls[i].lastIndexOf("/")+1).trim();
236 	    servletnames[i] = servleturls[i].substring(servleturls[i].lastIndexOf("/")+1).trim();
237 	    formselectionservleturls[i] = response.encodeURL(servlethosts[i] + "FormSelectionServlet");
238 
239 	    // invalidate entries which are not on the correct host
240 	    if (servlethost != null && !servlethosts[i].equals(servlethost)) {
241 		servletnames[i] = null;
242 		servlethosts[i] = null;
243 		formselectionservleturls[i] = null;
244 		formurls[i] = null;
245 		geometries[0][i] = null;
246 		geometries[1][i] = null;		    
247 	    }
248 
249 	    // invalidate double entries
250 	    if (formurls[i] != null && forms.contains(formurls[i] + "    " + servleturls[i])) {
251 		servletnames[i] = null;
252 		servlethosts[i] = null;
253 		formselectionservleturls[i] = null;
254 		formurls[i] = null;
255 		geometries[0][i] = null;
256 		geometries[1][i] = null;		    
257 	    }
258 
259 	    if (formurls[i] != null) {
260 		forms.add(formurls[i] + "    " + servleturls[i]);
261 		logger.info("Form: "+formurls[i]+", "+geometries[0][i]+"x"+geometries[1][i]);
262 	    }
263 	}
264 
265 	String js_formurls = buildJSArray(formurls, "\"");
266 	String js_servletnames = buildJSArray(servletnames, "\"");
267 	String js_formwidths = buildJSArray(geometries[0], "\"");
268 	String js_formheights = buildJSArray(geometries[1], "\"");
269 	String js_formselectionservleturls = buildJSArray(formselectionservleturls, "\"");
270 
271 	logger.info("Form URLs: "+js_formurls);
272 	logger.info("Servlet Names: "+js_servletnames);
273 	logger.info("Form Widths: "+js_formwidths);
274 	logger.info("Form Heights: "+js_formheights);
275 
276 	String js_genericservlet = null;
277 	String js_genericform = null;
278 	String js_genericform_width = null;
279 	String js_genericform_height = null;
280 	String js_genericformselectionservlet = null;
281 
282 	if (!XMLUtilities.isControlPlace(place)) {
283 	    js_genericservlet = "GenericDataServlet";
284 	    js_genericform = getProperty(KEY_GENERIC_FORM_URL);
285 	    js_genericform_width = getProperty(KEY_GENERIC_FORM_WIDTH);
286 	    js_genericform_height = getProperty(KEY_GENERIC_FORM_HEIGHT);
287 	    js_genericformselectionservlet = getProperty(KEY_SERVLET_BASE_URL)+"FormSelectionServlet";
288 	} else {
289 	    js_genericservlet = "DefaultDataServlet";
290 	    js_genericform = getProperty(KEY_CONTROL_TOKEN_FORM_URL);
291 	    js_genericform_width = getProperty(KEY_CONTROL_TOKEN_FORM_WIDTH);
292 	    js_genericform_height = getProperty(KEY_CONTROL_TOKEN_FORM_HEIGHT);
293 	    js_genericformselectionservlet = getProperty(KEY_SERVLET_BASE_URL)+"FormSelectionServlet";
294 	}
295 
296 	// read the template and replace all placeholders
297 	String form = ServletUtilities.readFile(getProperty(KEY_FORM_SELECTION_TEMPLATE_URL));
298 	
299 	form = ServletUtilities.replace(form, PLACEHOLDER_ADDITIONAL_PARAMETERS, js_additionalparameters);
300 	form = ServletUtilities.replace(form, PLACEHOLDER_FORM_URLS, js_formurls);
301 	form = ServletUtilities.replace(form, PLACEHOLDER_SERVLET_NAMES, js_servletnames);
302 	form = ServletUtilities.replace(form, PLACEHOLDER_FORM_WIDTHS, js_formwidths);
303 	form = ServletUtilities.replace(form, PLACEHOLDER_FORM_HEIGHTS, js_formheights);
304 	form = ServletUtilities.replace(form, PLACEHOLDER_FORMSELECTIONSERVLET_URLS, js_formselectionservleturls);
305 
306 	form = ServletUtilities.replace(form, PLACEHOLDER_GENERIC_SERVLET, js_genericservlet);
307 	form = ServletUtilities.replace(form, PLACEHOLDER_GENERIC_FORM, js_genericform);
308 	form = ServletUtilities.replace(form, PLACEHOLDER_GENERIC_FORM_WIDTH, js_genericform_width);
309 	form = ServletUtilities.replace(form, PLACEHOLDER_GENERIC_FORM_HEIGHT, js_genericform_height);
310 	form = ServletUtilities.replace(form, PLACEHOLDER_GENERIC_FORMSELECTIONSERVLET, js_genericformselectionservlet);
311 	
312 	form = ServletUtilities.replace(form, PLACEHOLDER_TEMPLATE_WIDTH, getProperty(KEY_FORM_SELECTION_TEMPLATE_WIDTH));
313 	form = ServletUtilities.replace(form, PLACEHOLDER_TEMPLATE_HEIGHT, getProperty(KEY_FORM_SELECTION_TEMPLATE_HEIGHT));
314 
315 	PrintWriter out = response.getWriter();
316 	out.println(form);
317 
318 	logger.info("Form: \n"+form);
319     }
320 
321     ///
322     /// Utilities
323     /// ....................................................................................................
324 
325     protected String buildJSArray(String[] parts, String quote) {
326 	StringBuffer s = new StringBuffer();
327 	for (int i=0; i<parts.length; i++) {	 
328 	    if (parts[i] != null) {
329 		s.append(quote).append(parts[i]).append(quote);
330 		s.append(",");
331 	    }
332 	}
333 	if (s.length()>0) s.deleteCharAt(s.length()-1);
334 	return s.toString();
335     }        
336 
337     protected String[] parseStringArray(String string) {
338 	if (string == null) 
339 	    return new String[0];
340 
341 	StringTokenizer z = new StringTokenizer(string, " ", false);
342 	String[] arr = new String[z.countTokens()];
343 	for (int i=0; z.hasMoreTokens(); i++) {
344 	    arr[i] = z.nextToken();
345 	}
346 
347 	return arr;
348     }
349 
350     protected String[][] parseGeometriesArray(String[] string) {
351 	if (string == null) 
352 	    return new String[2][0];
353 
354 	String[][] geo = new String[2][string.length];
355 	for (int i=0; i<string.length; i++) {
356 	    geo[0][i] = string[i].substring(0, string[i].indexOf("x"));
357 	    geo[1][i] = string[i].substring(string[i].indexOf("x")+1);	
358 	}
359 
360 	return geo;
361     }
362 }