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