View Javadoc

1   /*
2    * Copyright 2003,2004,2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.pluto.portlet.admin.services;
17  
18  import java.io.File;
19  import java.io.FileInputStream;
20  import java.io.FileNotFoundException;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.RandomAccessFile;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Properties;
32  import java.util.Set;
33  import java.util.zip.ZipEntry;
34  import java.util.zip.ZipFile;
35  
36  import javax.portlet.ActionRequest;
37  import javax.portlet.ActionResponse;
38  
39  import org.apache.commons.fileupload.FileItem;
40  import org.apache.commons.fileupload.FileUploadException;
41  import org.apache.commons.fileupload.PortletDiskFileUpload;
42  import org.apache.pluto.portlet.admin.BaseAdminObject;
43  import org.apache.pluto.portlet.admin.PlutoAdminConstants;
44  import org.apache.pluto.portlet.admin.PlutoAdminException;
45  import org.apache.pluto.portlet.admin.bean.PageTO;
46  import org.apache.pluto.portlet.admin.bean.PortletMessage;
47  import org.apache.pluto.portlet.admin.bean.PortletMessageType;
48  import org.apache.pluto.portlet.admin.bean.PortletTO;
49  import org.apache.pluto.portlet.admin.model.PageRegistryXao;
50  import org.apache.pluto.portlet.admin.model.PortletEntityRegistryXao;
51  import org.apache.pluto.portlet.admin.util.PlutoAdminContext;
52  
53  /***
54   * This is the service that does is called by DeployWarPortlet to
55   * do the work of deploying a portlet war.
56   *
57   * @author Ken Atherton
58   * @author Craig Doremus
59   *
60   */
61  public class DeployWarService extends BaseAdminObject {
62  
63      public static final String ERROR_NO_FILE = "ERROR_NO_FILE";
64  	public static final String CLASS_NAME = "DeployWarService";
65  
66  	/***
67  	 * Default constructor
68  	 */
69  	public DeployWarService() {
70  		super(CLASS_NAME);
71  	}
72  
73  	/***
74  	 * Constructor taking a String used to identify a logging record.
75  	 * @param logId
76  	 */
77  	public DeployWarService(String logId) {
78  		super(CLASS_NAME, logId);
79  	}
80  
81  	/***
82  	 * Does the work of this service to deploy a portlet war file.
83  	 * 
84  	 * @param request DeployWarService request object.
85  	 * @param response DeployWarService response object.
86  	 * @return
87  	 */
88    public String processFileUpload(ActionRequest request, ActionResponse response) {
89    	final String METHOD_NAME = "processFileUpload(request,response)";
90      String fileName = null;
91      String serverFileName = null;
92      request.getPortletSession().setAttribute(PlutoAdminConstants.MESSAGE_ATTR, new PortletMessage("Deployment unsuccessful", PortletMessageType.ERROR));
93      // Check the request content type to see if it starts with multipart/
94      if (PortletDiskFileUpload.isMultipartContent(request))
95      {
96  
97  	    PortletDiskFileUpload dfu = new PortletDiskFileUpload();
98  
99  	    //maximum allowed file upload size (10 MB)
100 	    dfu.setSizeMax(10 * 1000 * 1000);
101 
102 	    //maximum size in memory (vs disk) (100 KB)
103 	    dfu.setSizeThreshold(100 * 1000);
104 
105         try
106         {
107             //get the FileItems
108             List fileItems = dfu.parseRequest(request);
109             Iterator iter = fileItems.iterator();
110             while (iter.hasNext())
111             {
112                 FileItem item = (FileItem) iter.next();
113                 if (item.isFormField())
114                 {
115                     //pass along to render request
116                     String fieldName = item.getFieldName();
117                     String value = item.getString();
118                     response.setRenderParameter(fieldName, value);
119                 }
120                 else
121                 {
122                     //write the uploaded file to a new location
123                     fileName = item.getName();
124                     String contentType = item.getContentType();
125                     long size = item.getSize();
126                     response.setRenderParameter("size", Long.toString(size));
127                     response.setRenderParameter("contentType", contentType);
128                     String tempDir = System.getProperty("java.io.tmpdir");
129                     serverFileName = getRootFilename(File.separatorChar, fileName);
130                     File serverFile = new File(tempDir, serverFileName);
131                     item.write(serverFile);
132                     response.setRenderParameter("serverFileName",  serverFileName);
133 
134                     //Add to portletentityregistry.xml
135 					int index = serverFileName.indexOf(".war");
136 					String context = "";
137 					if ( index != -1) {
138 						context = serverFileName.substring(0, index);
139 					} else {
140 						context = serverFileName;
141 					}
142 			        //Check to see if a record exists
143   		            PortletEntityRegistryXao xao = new PortletEntityRegistryXao();
144 			        boolean appExists = xao.applicationExists(context);
145 					ArrayList  argList = createDeploymentArgs(serverFileName, tempDir, request, appExists);
146 					Map pmap = (HashMap) request.getPortletSession().getAttribute(PlutoAdminConstants.PORTLET_MAP_ATTR);
147 					logDebug(METHOD_NAME, "Arguments for Deploy.main():");
148 					String[] args = arrayListToStringArray(argList);
149 					for (int i =0; i < args.length; i++) {
150 						logDebug(METHOD_NAME, "args["+i+"]="+args[i]);
151 					}
152 		            org.apache.pluto.portalImpl.Deploy.main(args);
153 		            if (appExists) {
154 		            	request.getPortletSession().setAttribute(PlutoAdminConstants.MESSAGE_ATTR, new PortletMessage("Deployment of the new portlet app has been successful, but the portlet app record '" + context + "' already exists in portletentityregistry.xml. " +
155 		            			"This may have occurred if the portlet was previously partially deployed. If that is the case, continue with this screen and the next to register the portlet in pageregistry.xml. " +
156 		            			"If you are deploying a previously deployed portlet app, you should be able to see your changes if you select the portlet from the navigation bar. " +
157 		            			"However, caching of the old app may require that you restart Pluto to see the new changes.", PortletMessageType.INFO));
158 		            } else {
159 		            	request.getPortletSession().setAttribute(PlutoAdminConstants.MESSAGE_ATTR, new PortletMessage("Deployment and addition to portletentityregistry.xml successful.", PortletMessageType.SUCCESS));
160 		            }
161 		         }
162             }
163         }
164         catch (FileUploadException e){
165             String msg = "File Upload Exception: " + e.getMessage();
166             logError(METHOD_NAME, msg, e);
167             throw new PlutoAdminException(e);
168         } catch (Exception e) {
169             String msg = "Exception: " + e.getMessage();
170             logError(METHOD_NAME, msg, e);
171             throw new PlutoAdminException(e);
172         }
173     } else {
174         //set an error message
175       	request.getPortletSession().setAttribute(PlutoAdminConstants.MESSAGE_ATTR, new PortletMessage("No file appears to have been selected.", PortletMessageType.ERROR));
176     }
177     logMethodEnd(METHOD_NAME, serverFileName);
178     return serverFileName;
179   }
180 
181 
182   private String getRootFilename(char delimiter, String pathName) {
183     int startFilenameIndex = pathName.lastIndexOf(delimiter)  + 1;
184     String filename =  pathName.substring(startFilenameIndex);
185     return filename;
186   }
187 
188 	private static String[] arrayListToStringArray(ArrayList argStringArrayList) {
189 		return  (String[]) argStringArrayList.toArray(new String[argStringArrayList.size()]);
190 	}
191 
192 
193 
194 	private InputStream extractFile(String zipfilename, String filename) {
195   	final String METHOD_NAME = "extractFile(zipfilename,filename)";
196 	    InputStream ins = null;
197 	    try {
198 	        ZipFile zf = new ZipFile(zipfilename);
199 	        if (null != zf) {
200 	            ZipEntry ze = zf.getEntry(filename);
201 	            if (null != ze) {
202 	                ins = zf.getInputStream(ze);
203 	            }
204 	        }
205 	    }
206 	    catch (Exception e) {
207         logError(CLASS_NAME, METHOD_NAME, e);
208         throw new PlutoAdminException(e);
209 	    }
210 	    return ins;
211 	}
212 
213 
214 
215 	/***
216 	 * Creates arguments (parameters) for Deploy class that does
217 	 * the deployment.
218 	 *  
219 	 * @param serverFileName The name of the war file to be deployed
220 	 * @param tempDir Full path to temp dir that holds the war file to be deployed
221 	 * @param request ActionRequest of the portlet.
222 	 * @param appExists True if this is a re-deployment, else false
223 	 * @return ArrayList of arguments
224 	 * @throws Exception
225 	 * @see org.apache.pluto.portalImpl.Deploy#main
226 	 */
227 	private ArrayList createDeploymentArgs(String serverFileName, String tempDir, ActionRequest request, boolean appExists) throws Exception {
228 	  	final String METHOD_NAME = "createDeploymentArgs(serverFileName,tempDir,request)";
229 	  	Properties props = PlutoAdminContext.getProperties();
230 	    final String CONTAINER_HOME =  PlutoAdminContext.getContainerHome();
231 	    final String PORTLET_DEPLOY_DIR = props.getProperty("portlet-deploy-dir");
232 	
233 	    ArrayList  args = new ArrayList();
234 	    args.add(PlutoAdminContext.getDeploymentPath());
235 	    args.add(PlutoAdminContext.getPlutoWebContext());
236 	    args.add(tempDir + PlutoAdminConstants.FS + serverFileName);
237 	    //This is probably not used???, but left here to as to not change
238 	    //	args indexing used by Deploy class.
239 	    args.add(CONTAINER_HOME + PlutoAdminConstants.FS + PORTLET_DEPLOY_DIR);
240 	    String appId = PortletRegistryService.getNextAppId();
241 	    //check if a record in portletentityregistry exists
242 	    if (!appExists) {
243 		    args.add("-addToEntityReg");
244 		    args.add(appId);
245 	    }
246 	
247 	    //Add Map of portlet name/values to session
248 	    // to be used in drop downs on page layout page
249 	    Map pmap = new HashMap();
250 	    InputStream ins = extractFile(tempDir + PlutoAdminConstants.FS + serverFileName, "WEB-INF/portlet.xml");
251 	    if (null != ins) {
252 		    ArrayList names = PortletNameFinder.getPortletNames(ins);
253 		    for (int i = 0; i < names.size(); i++) {
254 		      //check if a record in portletentityregistry exists
255 		      if (!appExists) {
256 		      	args.add(i + ":" + names.get(i));
257 		      }
258 		      pmap.put(names.get(i), appId+"." +i);
259 		    }
260 		    ins.close();
261 	    } else {
262 	    	String msg = "Input stream is null";
263 	    	PlutoAdminException e = new PlutoAdminException(msg);
264 	    	logError(METHOD_NAME, e);
265 	    	throw e;
266 	    }
267 	    request.getPortletSession().setAttribute(PlutoAdminConstants.PORTLET_MAP_ATTR, pmap);
268 	    return args;
269 	}
270 
271 
272 	public static String mapToEntrySetString(Map inputMap) {
273     StringBuffer sb = new StringBuffer();
274     Set es = inputMap.entrySet();
275     Iterator it = es.iterator();
276     sb.append("Number of entries: " +  es.size());
277     for (int i = 0; i < es.size(); i++) {
278         Map.Entry entry = (Map.Entry) it.next();
279         sb.append((String) entry.getKey().toString());
280         sb.append(entry.getValue().toString());
281         sb.append("\n");
282     }
283     return sb.toString();
284 	}
285 
286 	/***
287 	 * Sets the page information into a PageTO object that is loaded into the
288 	 * session.
289 	 *
290 	 * @param req
291 	 */
292 	public void setPage(ActionRequest req) {
293 		final String METHOD_NAME = "setPage(request)";
294 		logMethodStart(METHOD_NAME);
295 		PageTO page = (PageTO)req.getPortletSession().getAttribute(PlutoAdminConstants.PAGE_ATTR);
296 		if (page == null) {
297 			page = new PageTO();
298 		}
299 		String title = req.getParameter("title");
300 //		logDebug(METHOD_NAME, "Title: " + title);
301 		page.setTitle(title);
302 		String desc = req.getParameter("description");
303 //		logDebug(METHOD_NAME, "Description: " + desc);
304 		page.setDescription(desc);
305 		String rows = req.getParameter("numrows");
306 //		logDebug(METHOD_NAME, "Row count: " + rows);
307 		page.setRows(Integer.parseInt(rows));
308 		String cols = req.getParameter("numcols");
309 //		logDebug(METHOD_NAME, "Col count: " + cols);
310 		page.setCols(Integer.parseInt(cols));
311 		req.getPortletSession().setAttribute(PlutoAdminConstants.PAGE_ATTR, page);
312 //		logDebug(METHOD_NAME, "New page: " + page);
313 		logMethodEnd(METHOD_NAME);
314 	}
315 	public void savePageLayout(ActionRequest req) {
316 		final String METHOD_NAME = "savePageLayout(request)";
317 		logMethodStart(METHOD_NAME);
318 		//get current page
319 		PageTO page = (PageTO)req.getPortletSession().getAttribute(PlutoAdminConstants.PAGE_ATTR);
320 //		logDebug(METHOD_NAME, "PageTO from session: " + page);
321 		List list = new ArrayList();
322 		int rows = page.getRows();
323 		int cols = page.getCols();
324 	    for (int i = 1; i <= rows ; i++) {
325 	      for (int j = 1; j <= cols ; j++) {
326 	      	String portletParam = "portlet" + i + "." + j;
327 	      	String name_val = req.getParameter(portletParam);
328 	      	//portlet name and values are separated by an underscore
329 	      	int underscore = name_val.lastIndexOf("_");
330 	      	String name = name_val.substring(0, underscore);
331 	      	String val = name_val.substring(underscore + 1);
332 	
333 	      	//create a PortletTO and add it to the list
334 	      	PortletTO nPortlet = new PortletTO();
335 	      	nPortlet.setName(name);
336 	      	nPortlet.setValue(val);
337 	      	nPortlet.setRow(i);
338 	      	nPortlet.setCol(j);
339 	      	list.add(nPortlet);
340 	      }
341 	    }
342 	    page.setPortlets(list);
343 //		logDebug(METHOD_NAME, "Updated PageTO: " + page);
344 
345 		addToPageReg(page);
346 		logMethodEnd(METHOD_NAME);
347 	}
348 
349 	/***
350 	 * Add a new page record to the pageregistry.xml file.
351 	 * @param page The new page to add
352 	 */
353   public void addToPageReg(PageTO page) {
354 		final String METHOD_NAME = "addToPageReg(PageTO)";
355 		logMethodStart(METHOD_NAME);
356 		RandomAccessFile ras = null;
357 
358 //		int rows = page.getRows();
359 		int cols = page.getCols();
360 		String name = page.getName();
361 	  try {
362 			  	//get path to pageregistry.xml
363 			String pageregpath = PlutoAdminContext.getInstance().getPageRegistryPath();
364 			//String pageregpath = "/pluto-1.0.1/webapps/pluto/WEB-INF/data/pageregistry.xml";
365 
366 			File file = new File(pageregpath);
367 			ras = new RandomAccessFile(file, "rw");
368 			long length = ras.length();
369 			byte[] contentByte = new byte[(int) length];
370 			ras.read(contentByte);
371 			String contentString = new String(contentByte);
372 			//Check for previous deployment in pageregistry.xml
373 			String prev = "fragment name=\"" + name;
374 			if (contentString.lastIndexOf(prev) != -1){
375 				String errMsg = "Portlet '" + name + "' already exists in pageregistry.xml";
376 				PlutoAdminException e = new PlutoAdminException(errMsg);
377 				logError(METHOD_NAME, errMsg, e);
378 				throw e;//throw exception here
379 			}
380 			//start before close of root element
381 			long pos = contentString.lastIndexOf("</portal>");
382 			ras.seek(pos);
383 
384 			//start page fragment
385 			ras.writeBytes("    <fragment name=\"" + name + "\" type=\"page\" >" + PlutoAdminConstants.LS);
386 			ras.writeBytes("        <navigation>" + PlutoAdminConstants.LS);
387 			ras.writeBytes("	        <title>" + page.getTitle());
388 			ras.writeBytes("</title>" + PlutoAdminConstants.LS);
389 			ras.writeBytes("	        <description>" + page.getDescription());
390 			ras.writeBytes("</description>" + PlutoAdminConstants.LS);
391 			ras.writeBytes("        </navigation>" + PlutoAdminConstants.LS);
392 
393 			//iterate through portlets
394 			List portlets = page.getPortlets();
395 			//Sort list using Comparable implementation in PortletTO. This makes sure
396 			//	the items in the list are ordered by rows
397 			Collections.sort(portlets);
398 			Iterator iter = portlets.iterator();
399 			int count = 0;
400 			int currRow = 0;
401 			int lastRow = 0;
402 			int currCol = 0;
403 			while (iter.hasNext()) {
404 					count++;
405 					PortletTO portlet = (PortletTO)iter.next();
406 					logDebug(METHOD_NAME, "Portlet: " + portlet);
407 					currRow = portlet.getRow();
408 					currCol = portlet.getCol();
409 					//start row fragment
410 					//	Add row fragment when row changes
411 					if (currRow != lastRow) {
412 						ras.writeBytes("          <fragment name=\"row" + currRow + "\" type=\"row\">" + PlutoAdminConstants.LS);
413 						ras.writeBytes("             <fragment name=\"col" + count + "\" type=\"column\">" + PlutoAdminConstants.LS);
414 					}
415 
416 						ras.writeBytes("                  <fragment name=\"p" + count + "\" type=\"portlet\">" + PlutoAdminConstants.LS);
417 						ras.writeBytes("                    <property name=\"portlet\" value=\"" + portlet.getValue() + "\"/>" + PlutoAdminConstants.LS);
418 						ras.writeBytes("                  </fragment><!-- end of portlet frag -->" + PlutoAdminConstants.LS);
419 
420 						//end row fragment
421 						if (cols == currCol) {
422 							ras.writeBytes("             </fragment><!-- end of col frag -->" + PlutoAdminConstants.LS);
423 							//end of column iteration
424 							ras.writeBytes("         </fragment><!-- end of row frag -->" + PlutoAdminConstants.LS);
425 						}
426 					lastRow = currRow;
427 			}
428 
429 			//end page fragment
430 			ras.writeBytes("    </fragment><!-- end of 'page' frag -->" + PlutoAdminConstants.LS);
431 			//add a couple of newlines to separate records
432 			ras.writeBytes(PlutoAdminConstants.LS);
433 			ras.writeBytes(PlutoAdminConstants.LS);
434 			//replace closing root element
435 			ras.writeBytes("</portal>" + PlutoAdminConstants.LS);
436 
437 		} catch (IOException e) {
438 				logError(METHOD_NAME, e);
439 				throw new PlutoAdminException(e);
440 		} finally {
441 			if (ras != null) {
442 				try {
443 					ras.close();
444 				} catch (IOException e) {
445 					logError(METHOD_NAME, e);
446 				}
447 			}
448 		}
449 		logMethodEnd(METHOD_NAME);
450   }
451 
452   public boolean addToPortletContexts(String context) {
453   	final String METHOD_NAME = "addToPortletContexts(context)";
454 	logMethodStart(METHOD_NAME);
455   	logParam(METHOD_NAME, "context", context);
456   	String path = PlutoAdminContext.getInstance().getPortletContextsPath();
457   	logDebug(METHOD_NAME, "portletcontexts.txt path: " + path);
458   	File file = new File(path);
459 		boolean found = false;
460   	if (file.exists()) { //check for Pluto 1.0.1-rc1
461 			String fileContents = readFileToString(file);
462 			logDebug(METHOD_NAME, "portletcontexts.txt contents: " + fileContents);
463 
464 			//Check to see whether the context already is found in 
465 			//	the portletcontexts.txt file.
466 			int ind = fileContents.indexOf(context);
467 			found = ind == -1 ? false : true;
468 
469 			//Make sure that context name is not a substring of 
470 			//	another context name. For example, /foo ,
471 			//	/foobar and /barfoo are all valid contexts.
472 			//check if a slash before the found context name in portletcontexts.txt file
473 			if (found && !fileContents.substring(ind - 1, ind).equals("/")) {
474 			    found = false;
475 			}
476 			//check if there is a line-separator after the found context name in portletcontexts.txt file
477 			if (found) {
478 			    int len = context.length();//length of context String
479 			    String contextInFile = fileContents.substring(ind);//substring that starts with context
480 			    if (contextInFile.indexOf(PlutoAdminConstants.LS) != len) {
481 				    found = false;			        
482 			    }
483 			}
484 			if (!found) {
485 				logDebug(METHOD_NAME, "Writing new context: " + context);
486 				StringBuffer buf = new StringBuffer(fileContents);
487 				buf.append(PlutoAdminConstants.LS);
488 				buf.append("/");
489 				buf.append(context);
490 				writeStringToFile(file,buf.toString());
491 			}
492   	} else {
493 			logWarn(METHOD_NAME, "File portletcontexts.txt cannot be found! You must be using Release Candidate 1.");
494   	}
495 	logMethodEnd(METHOD_NAME, Boolean.toString(found));
496 	return found;
497   }
498 
499 
500   public boolean pageExists(String pageName) {
501   	final String METHOD_NAME = "pageExists(pageName)";
502   	boolean exists = true;
503   	try {
504 			PageRegistryXao xao = new PageRegistryXao();
505 			exists = xao.pageExists(pageName);
506 		} catch (Exception e) {
507 			logError(METHOD_NAME, e);
508 			throw new PlutoAdminException(e);
509 		}
510   	return exists;
511   }
512 
513   public String readFileToString(File file){
514   	final String METHOD_NAME = "readFileToString(path)";
515   	String contents = null;
516 		FileInputStream fis = null;
517   	try {
518 			fis = new FileInputStream(file);
519 			int c;
520 			char b;
521 			StringBuffer sb = new StringBuffer();
522 			while((c = fis.read()) != -1) {
523 				b = (char)c;
524 				sb.append(b);
525 			}
526 			contents = sb.toString().trim();
527 		} catch (FileNotFoundException e) {
528 			logError(METHOD_NAME, e);
529 			throw new PlutoAdminException(e);
530 		} catch (IOException e) {
531 			logError(METHOD_NAME, e);
532 			throw new PlutoAdminException(e);
533 		}	finally {
534 			if (fis != null) {
535 				try {
536 					fis.close();
537 				} catch (IOException e) {
538 					logError(METHOD_NAME, e);
539 					throw new PlutoAdminException(e);
540 				}
541 			}
542 		}
543   	return contents;
544   }
545 
546   public void writeStringToFile(File file, String contents){
547   	final String METHOD_NAME = "addFileToStringToFile(contents)";
548 		FileOutputStream fos = null;
549   	try {
550 			fos = new FileOutputStream(file);
551 			byte[] bytes = contents.getBytes();
552 			fos.write(bytes);
553 		} catch (FileNotFoundException e) {
554 			logError(METHOD_NAME, e);
555 			throw new PlutoAdminException(e);
556 		} catch (IOException e) {
557 			logError(METHOD_NAME, e);
558 			throw new PlutoAdminException(e);
559 		}	finally {
560 			if (fos != null) {
561 				try {
562 					fos.close();
563 				} catch (IOException e) {
564 					logError(METHOD_NAME, e);
565 					throw new PlutoAdminException(e);
566 				}
567 			}
568 		}
569   }
570 
571 }