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.descriptors.portlet.PortletDD;
43  import org.apache.pluto.portalImpl.om.entity.impl.PortletApplicationEntityImpl;
44  import org.apache.pluto.portlet.admin.BaseAdminObject;
45  import org.apache.pluto.portlet.admin.PlutoAdminConstants;
46  import org.apache.pluto.portlet.admin.PlutoAdminException;
47  import org.apache.pluto.portlet.admin.bean.PageTO;
48  import org.apache.pluto.portlet.admin.bean.PortletMessage;
49  import org.apache.pluto.portlet.admin.bean.PortletMessageType;
50  import org.apache.pluto.portlet.admin.bean.PortletTO;
51  import org.apache.pluto.portlet.admin.model.PageRegistryXao;
52  import org.apache.pluto.portlet.admin.model.PortletEntityRegistryXao;
53  import org.apache.pluto.portlet.admin.util.PlutoAdminContext;
54  
55  /***
56   * This is the service that does is called by DeployWarPortlet to
57   * do the work of deploying a portlet war.
58   *
59   * @author Ken Atherton
60   * @author Craig Doremus
61   *
62   */
63  public class DeployWarService extends BaseAdminObject {
64  
65      public static final String ERROR_NO_FILE = "ERROR_NO_FILE";
66  	public static final String CLASS_NAME = "DeployWarService";
67  
68  	/***
69  	 * Default constructor
70  	 */
71  	public DeployWarService() {
72  		super(CLASS_NAME);
73  	}
74  
75  	/***
76  	 * Constructor taking a String used to identify a logging record.
77  	 * @param logId
78  	 */
79  	public DeployWarService(String logId) {
80  		super(CLASS_NAME, logId);
81  	}
82  
83  	/***
84  	 * Does the work of this service to deploy a portlet war file.
85  	 * 
86  	 * @param request DeployWarService request object.
87  	 * @param response DeployWarService response object.
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      boolean modifyWebXml = true;
94      request.getPortletSession().setAttribute(PlutoAdminConstants.MESSAGE_ATTR, new PortletMessage("Deployment unsuccessful", PortletMessageType.ERROR));
95      // Check the request content type to see if it starts with multipart/
96      if (PortletDiskFileUpload.isMultipartContent(request))
97      {
98  
99  	    PortletDiskFileUpload dfu = new PortletDiskFileUpload();
100 
101 	    //maximum allowed file upload size (10 MB)
102 	    dfu.setSizeMax(10 * 1000 * 1000);
103 
104 	    //maximum size in memory (vs disk) (100 KB)
105 	    dfu.setSizeThreshold(100 * 1000);
106 
107         try
108         {
109             //get the FileItems
110             List fileItems = dfu.parseRequest(request);
111             Iterator iter = fileItems.iterator();
112             while (iter.hasNext())
113             {
114                 FileItem item = (FileItem) iter.next();
115                 if (item.isFormField())
116                 {
117                     //pass along to render request
118                     String fieldName = item.getFieldName();
119                     String value = item.getString();
120                     response.setRenderParameter(fieldName, value);
121                     if (fieldName.equalsIgnoreCase("NoWebXmlModification")) {
122                         String noWebXmlModification = item.getString();
123                         logWarn(METHOD_NAME, "Don't modify web.xml? " + noWebXmlModification);
124                         if (noWebXmlModification != null) {
125                         	modifyWebXml = false;
126                         }
127                     }
128                 }
129                 else
130                 {
131                     //write the uploaded file to a new location
132                     fileName = item.getName();
133                     String contentType = item.getContentType();
134                     long size = item.getSize();
135                     response.setRenderParameter("size", Long.toString(size));
136                     response.setRenderParameter("contentType", contentType);
137                     String tempDir = System.getProperty("java.io.tmpdir");
138                     serverFileName = getRootFilename(File.separatorChar, fileName);
139                     File serverFile = new File(tempDir, serverFileName);
140                     item.write(serverFile);
141                     response.setRenderParameter("serverFileName",  serverFileName);
142 
143                     //Add to portletentityregistry.xml
144 					int index = serverFileName.indexOf(".war");
145 					String context = "";
146 					if ( index != -1) {
147 						context = serverFileName.substring(0, index);
148 					} else {
149 						context = serverFileName;
150 					}
151 			        //Check to see if a record exists
152   		            PortletEntityRegistryXao xao = new PortletEntityRegistryXao();
153 			        boolean appExists = xao.applicationExists(context);
154 					ArrayList  argList = createDeploymentArgs(serverFileName, tempDir, request, appExists, context);
155 					Map pmap = (HashMap) request.getPortletSession().getAttribute(PlutoAdminConstants.PORTLET_MAP_ATTR);
156 					logDebug(METHOD_NAME, "Arguments for Deploy.main():");
157 					String[] args = arrayListToStringArray(argList);
158 					for (int i =0; i < args.length; i++) {
159 						logDebug(METHOD_NAME, "args["+i+"]="+args[i]);
160 					}
161 		            org.apache.pluto.portalImpl.Deploy.main(args);
162 		            //NEW: Update web.xml with new servlet elements
163 		            if (modifyWebXml) {
164 		            	updateWebXml(context);
165 		            }
166 		            if (appExists) {
167 		            	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. " +
168 		            			"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. " +
169 		            			"If you are deploying a previously deployed portlet app, click on the 'Deploy War home' link below and then the 'Hot deploy . . .' link on the resulting page to see your redeployed portlet. " +
170 		            			"However, caching of the old app may require that you restart Pluto to see the new changes.", PortletMessageType.INFO));
171 		            } else {
172 		            	request.getPortletSession().setAttribute(PlutoAdminConstants.MESSAGE_ATTR, new PortletMessage("Deployment and addition to portletentityregistry.xml successful.", PortletMessageType.SUCCESS));
173 		            }
174 		         }
175             }
176         }
177         catch (FileUploadException e){
178             String msg = "File Upload Exception: " + e.getMessage();
179             logError(METHOD_NAME, msg, e);
180             throw new PlutoAdminException(e);
181         } catch (Exception e) {
182             String msg = "Exception: " + e.getMessage();
183             logError(METHOD_NAME, msg, e);
184             throw new PlutoAdminException(e);
185         }
186     } else {
187         //set an error message
188       	request.getPortletSession().setAttribute(PlutoAdminConstants.MESSAGE_ATTR, new PortletMessage("No file appears to have been selected.", PortletMessageType.ERROR));
189     }
190     logMethodEnd(METHOD_NAME, serverFileName);
191     return serverFileName;
192   }
193 
194 
195   private String getRootFilename(char delimiter, String pathName) {
196     int startFilenameIndex = pathName.lastIndexOf(delimiter)  + 1;
197     String filename =  pathName.substring(startFilenameIndex);
198     return filename;
199   }
200 
201 	private static String[] arrayListToStringArray(ArrayList argStringArrayList) {
202 		return  (String[]) argStringArrayList.toArray(new String[argStringArrayList.size()]);
203 	}
204 
205 
206 
207 	private InputStream extractFile(String zipfilename, String filename) {
208   	final String METHOD_NAME = "extractFile(zipfilename,filename)";
209 	    InputStream ins = null;
210 	    try {
211 	        ZipFile zf = new ZipFile(zipfilename);
212 	        if (null != zf) {
213 	            ZipEntry ze = zf.getEntry(filename);
214 	            if (null != ze) {
215 	                ins = zf.getInputStream(ze);
216 	            }
217 	        }
218 	    }
219 	    catch (Exception e) {
220         logError(CLASS_NAME, METHOD_NAME, e);
221         throw new PlutoAdminException(e);
222 	    }
223 	    return ins;
224 	}
225 
226 
227 
228 	/***
229 	 * Creates arguments (parameters) for Deploy class that does
230 	 * the deployment.
231 	 *  
232 	 * @param serverFileName The name of the war file to be deployed
233 	 * @param tempDir Full path to temp dir that holds the war file to be deployed
234 	 * @param request ActionRequest of the portlet.
235 	 * @param appExists True if this is a re-deployment, else false
236 	 * @return ArrayList of arguments
237 	 * @throws Exception
238 	 * @see org.apache.pluto.portalImpl.Deploy#main
239 	 */
240 	private ArrayList createDeploymentArgs(String serverFileName, String tempDir, ActionRequest request, boolean appExists, String context) throws Exception {
241 	  	final String METHOD_NAME = "createDeploymentArgs(serverFileName,tempDir,request)";
242 	  	Properties props = PlutoAdminContext.getProperties();
243 	    final String CONTAINER_HOME =  PlutoAdminContext.getContainerHome();
244 	    final String PORTLET_DEPLOY_DIR = props.getProperty("portlet-deploy-dir");
245 	
246 	    ArrayList  args = new ArrayList();
247 	    args.add(PlutoAdminContext.getDeploymentPath());
248 	    args.add(PlutoAdminContext.getPlutoWebContext());
249 	    args.add(tempDir + PlutoAdminConstants.FS + serverFileName);
250 	    //This is probably not used???, but left here to as to not change
251 	    //	args indexing used by Deploy class.
252 	    args.add(CONTAINER_HOME + PlutoAdminConstants.FS + PORTLET_DEPLOY_DIR);
253 	    String appId = PortletRegistryService.getNextAppId();
254 	    //check if a record in portletentityregistry exists
255 	    if (!appExists) {
256 		    args.add("-addToEntityReg");
257 		    args.add(appId);
258 	    } else {
259 	        //Don't add it to portletentityregistry.xml,
260 	        //and retreive id using webapp context and XAO
261 			PortletEntityRegistryXao xao = new PortletEntityRegistryXao();
262 			PortletApplicationEntityImpl app = xao.getApplication(context);
263 		    appId = app.getCastorId();
264 	    }
265 	
266 	    //Add Map of portlet name/values to session
267 	    // to be used in drop downs on page layout page
268 	    Map pmap = new HashMap();
269 	    InputStream ins = extractFile(tempDir + PlutoAdminConstants.FS + serverFileName, "WEB-INF/portlet.xml");
270 	    if (null != ins) {
271 		    ArrayList names = PortletNameFinder.getPortletNames(ins);
272 		    for (int i = 0; i < names.size(); i++) {
273 		      //check if a record in portletentityregistry exists
274 		      if (!appExists) {
275 		      	args.add(i + ":" + names.get(i));
276 		      }
277 		      pmap.put(names.get(i), appId+"." +i);
278 		    }
279 		    ins.close();
280 	    } else {
281 	    	String msg = "Input stream is null";
282 	    	PlutoAdminException e = new PlutoAdminException(msg);
283 	    	logError(METHOD_NAME, e);
284 	    	throw e;
285 	    }
286 	    request.getPortletSession().setAttribute(PlutoAdminConstants.PORTLET_MAP_ATTR, pmap);
287 	    return args;
288 	}
289 
290 
291 	public static String mapToEntrySetString(Map inputMap) {
292     StringBuffer sb = new StringBuffer();
293     Set es = inputMap.entrySet();
294     Iterator it = es.iterator();
295     sb.append("Number of entries: " +  es.size());
296     for (int i = 0; i < es.size(); i++) {
297         Map.Entry entry = (Map.Entry) it.next();
298         sb.append(entry.getKey().toString());
299         sb.append(entry.getValue().toString());
300         sb.append("\n");
301     }
302     return sb.toString();
303 	}
304 
305 	/***
306 	 * Sets the page information into a PageTO object that is loaded into the
307 	 * session.
308 	 *
309 	 * @param req
310 	 */
311 	public void setPage(ActionRequest req) {
312 		final String METHOD_NAME = "setPage(request)";
313 		logMethodStart(METHOD_NAME);
314 		PageTO page = (PageTO)req.getPortletSession().getAttribute(PlutoAdminConstants.PAGE_ATTR);
315 		if (page == null) {
316 			page = new PageTO();
317 		}
318 		String title = req.getParameter("title");
319 //		logDebug(METHOD_NAME, "Title: " + title);
320 		page.setTitle(title);
321 		String desc = req.getParameter("description");
322 //		logDebug(METHOD_NAME, "Description: " + desc);
323 		page.setDescription(desc);
324 		String rows = req.getParameter("numrows");
325 //		logDebug(METHOD_NAME, "Row count: " + rows);
326 		page.setRows(Integer.parseInt(rows));
327 		String cols = req.getParameter("numcols");
328 //		logDebug(METHOD_NAME, "Col count: " + cols);
329 		page.setCols(Integer.parseInt(cols));
330 		req.getPortletSession().setAttribute(PlutoAdminConstants.PAGE_ATTR, page);
331 //		logDebug(METHOD_NAME, "New page: " + page);
332 		logMethodEnd(METHOD_NAME);
333 	}
334 
335 	public void savePageLayout(ActionRequest req) {
336 		final String METHOD_NAME = "savePageLayout(request)";
337 		logMethodStart(METHOD_NAME);
338 		//get current page
339 		PageTO page = (PageTO)req.getPortletSession().getAttribute(PlutoAdminConstants.PAGE_ATTR);
340 //		logDebug(METHOD_NAME, "PageTO from session: " + page);
341 		List list = new ArrayList();
342 		int rows = page.getRows();
343 		int cols = page.getCols();
344 	    for (int i = 1; i <= rows ; i++) {
345 	      for (int j = 1; j <= cols ; j++) {
346 	      	String portletParam = "portlet" + i + "." + j;
347 	      	String name_val = req.getParameter(portletParam);
348 	      	//portlet name and values are separated by an underscore
349 	      	int underscore = name_val.lastIndexOf("_");
350 	      	String name = name_val.substring(0, underscore);
351 	      	String val = name_val.substring(underscore + 1);
352 	
353 	      	//create a PortletTO and add it to the list
354 	      	PortletTO nPortlet = new PortletTO();
355 	      	nPortlet.setName(name);
356 	      	nPortlet.setValue(val);
357 	      	nPortlet.setRow(i);
358 	      	nPortlet.setCol(j);
359 	      	list.add(nPortlet);
360 	      }
361 	    }
362 	    page.setPortlets(list);
363 //		logDebug(METHOD_NAME, "Updated PageTO: " + page);
364 
365 		addToPageReg(page);
366 		logMethodEnd(METHOD_NAME);
367 	}
368 
369 	/***
370 	 * Add a new page record to the pageregistry.xml file.
371 	 * @param page The new page to add
372 	 */
373   public void addToPageReg(PageTO page) {
374 		final String METHOD_NAME = "addToPageReg(PageTO)";
375 		logMethodStart(METHOD_NAME);
376 		RandomAccessFile ras = null;
377 
378 //		int rows = page.getRows();
379 		int cols = page.getCols();
380 		String name = page.getName();
381 	  try {
382 			  	//get path to pageregistry.xml
383 			String pageregpath = PlutoAdminContext.getInstance().getPageRegistryPath();
384 			//String pageregpath = "/pluto-1.0.1/webapps/pluto/WEB-INF/data/pageregistry.xml";
385 
386 			File file = new File(pageregpath);
387 			ras = new RandomAccessFile(file, "rw");
388 			long length = ras.length();
389 			byte[] contentByte = new byte[(int) length];
390 			ras.read(contentByte);
391 			String contentString = new String(contentByte);
392 			//Check for previous deployment in pageregistry.xml
393 			String prev = "fragment name=\"" + name;
394 			if (contentString.lastIndexOf(prev) != -1){
395 				String errMsg = "Portlet '" + name + "' already exists in pageregistry.xml";
396 				PlutoAdminException e = new PlutoAdminException(errMsg);
397 				logError(METHOD_NAME, errMsg, e);
398 				throw e;//throw exception here
399 			}
400 			//start before close of root element
401 			long pos = contentString.lastIndexOf("</portal>");
402 			ras.seek(pos);
403 
404 			//start page fragment
405 			ras.writeBytes("    <fragment name=\"" + name + "\" type=\"page\" >" + PlutoAdminConstants.LS);
406 			ras.writeBytes("        <navigation>" + PlutoAdminConstants.LS);
407 			ras.writeBytes("	        <title>" + page.getTitle());
408 			ras.writeBytes("</title>" + PlutoAdminConstants.LS);
409 			ras.writeBytes("	        <description>" + page.getDescription());
410 			ras.writeBytes("</description>" + PlutoAdminConstants.LS);
411 			ras.writeBytes("        </navigation>" + PlutoAdminConstants.LS);
412 
413 			//iterate through portlets
414 			List portlets = page.getPortlets();
415 			//Sort list using Comparable implementation in PortletTO. This makes sure
416 			//	the items in the list are ordered by rows
417 			Collections.sort(portlets);
418 			Iterator iter = portlets.iterator();
419 			int count = 0;
420 			int currRow = 0;
421 			int lastRow = 0;
422 			int currCol = 0;
423 			while (iter.hasNext()) {
424 					count++;
425 					PortletTO portlet = (PortletTO)iter.next();
426 					logDebug(METHOD_NAME, "Portlet: " + portlet);
427 					currRow = portlet.getRow();
428 					currCol = portlet.getCol();
429 					//start row fragment
430 					//	Add row fragment when row changes
431 					if (currRow != lastRow) {
432 						ras.writeBytes("          <fragment name=\"row" + currRow + "\" type=\"row\">" + PlutoAdminConstants.LS);
433 						ras.writeBytes("             <fragment name=\"col" + count + "\" type=\"column\">" + PlutoAdminConstants.LS);
434 					}
435 
436 						ras.writeBytes("                  <fragment name=\"p" + count + "\" type=\"portlet\">" + PlutoAdminConstants.LS);
437 						ras.writeBytes("                    <property name=\"portlet\" value=\"" + portlet.getValue() + "\"/>" + PlutoAdminConstants.LS);
438 						ras.writeBytes("                  </fragment><!-- end of portlet frag -->" + PlutoAdminConstants.LS);
439 
440 						//end row fragment
441 						if (cols == currCol) {
442 							ras.writeBytes("             </fragment><!-- end of col frag -->" + PlutoAdminConstants.LS);
443 							//end of column iteration
444 							ras.writeBytes("         </fragment><!-- end of row frag -->" + PlutoAdminConstants.LS);
445 						}
446 					lastRow = currRow;
447 			}
448 
449 			//end page fragment
450 			ras.writeBytes("    </fragment><!-- end of 'page' frag -->" + PlutoAdminConstants.LS);
451 			//add a couple of newlines to separate records
452 			ras.writeBytes(PlutoAdminConstants.LS);
453 			ras.writeBytes(PlutoAdminConstants.LS);
454 			//replace closing root element
455 			ras.writeBytes("</portal>" + PlutoAdminConstants.LS);
456 
457 		} catch (IOException e) {
458 				logError(METHOD_NAME, e);
459 				throw new PlutoAdminException(e);
460 		} finally {
461 			if (ras != null) {
462 				try {
463 					ras.close();
464 				} catch (IOException e) {
465 					logError(METHOD_NAME, e);
466 				}
467 			}
468 		}
469 		logMethodEnd(METHOD_NAME);
470   }
471 
472   public boolean addToPortletContexts(String context) {
473   	final String METHOD_NAME = "addToPortletContexts(context)";
474 	logMethodStart(METHOD_NAME);
475   	logParam(METHOD_NAME, "context", context);
476   	String path = PlutoAdminContext.getInstance().getPortletContextsPath();
477   	logDebug(METHOD_NAME, "portletcontexts.txt path: " + path);
478   	File file = new File(path);
479 		boolean found = false;
480   	if (file.exists()) { //check for Pluto 1.0.1-rc1
481 			String fileContents = readFileToString(file);
482 			logDebug(METHOD_NAME, "portletcontexts.txt contents: " + fileContents);
483 
484 			//Check to see whether the context already is found in 
485 			//	the portletcontexts.txt file.
486 			int ind = fileContents.indexOf(context);
487 			found = ind == -1 ? false : true;
488 
489 			//Make sure that context name is not a substring of 
490 			//	another context name. For example, /foo ,
491 			//	/foobar and /barfoo are all valid contexts.
492 			//check if a slash before the found context name in portletcontexts.txt file
493 			if (found && !fileContents.substring(ind - 1, ind).equals("/")) {
494 			    found = false;
495 			}
496 			//check if there is a line-separator after the found context name in portletcontexts.txt file
497 			// or that this context is the last token in the file
498 			if (found) {
499 			    int len = context.length();//length of context String
500 			    String contextInFile = fileContents.substring(ind);//substring that starts with context
501 			    int indLS = contextInFile.indexOf(PlutoAdminConstants.LS);
502 			    long fileLen = file.length(); //length of file
503 			    if ((indLS != len) && (ind + len != fileLen) ) {
504 				    found = false;			        
505 			    }
506 			}
507 			if (!found) {
508 				logDebug(METHOD_NAME, "Writing new context: " + context);
509 				StringBuffer buf = new StringBuffer(fileContents);
510 				buf.append(PlutoAdminConstants.LS);
511 				buf.append("/");
512 				buf.append(context);
513 				writeStringToFile(file,buf.toString());
514 			}
515   	} else {
516 			logWarn(METHOD_NAME, "File portletcontexts.txt cannot be found! You must be using Release Candidate 1.");
517   	}
518 	logMethodEnd(METHOD_NAME, Boolean.toString(found));
519 	return found;
520   }
521 
522 
523   public boolean pageExists(String pageName) {
524   	final String METHOD_NAME = "pageExists(pageName)";
525   	boolean exists = true;
526   	try {
527 			PageRegistryXao xao = new PageRegistryXao();
528 			exists = xao.pageExists(pageName);
529 		} catch (Exception e) {
530 			logError(METHOD_NAME, e);
531 			throw new PlutoAdminException(e);
532 		}
533   	return exists;
534   }
535 
536   /***
537    * Puts the contents of a file into a String. This only works
538    * with text files.
539    * 
540    * @param file The File to read
541    * @return A String containing the contents of the file.
542    */
543   public String readFileToString(File file){
544   	final String METHOD_NAME = "readFileToString(path)";
545   	String contents = null;
546 		FileInputStream fis = null;
547   	try {
548 			fis = new FileInputStream(file);
549 			int c;
550 			char b;
551 			StringBuffer sb = new StringBuffer();
552 			while((c = fis.read()) != -1) {
553 				b = (char)c;
554 				sb.append(b);
555 			}
556 			contents = sb.toString().trim();
557 		} catch (FileNotFoundException e) {
558 			logError(METHOD_NAME, e);
559 			throw new PlutoAdminException(e);
560 		} catch (IOException e) {
561 			logError(METHOD_NAME, e);
562 			throw new PlutoAdminException(e);
563 		}	finally {
564 			if (fis != null) {
565 				try {
566 					fis.close();
567 				} catch (IOException e) {
568 					logError(METHOD_NAME, e);
569 					throw new PlutoAdminException(e);
570 				}
571 			}
572 		}
573   	return contents;
574   }
575 
576   /***
577    * Writes the contents of a file into a String.
578    * 
579    * @param file Te File to write.
580    * @param contents The String to add to the file.
581    */
582   public void writeStringToFile(File file, String contents){
583   	final String METHOD_NAME = "addFileToStringToFile(contents)";
584 		FileOutputStream fos = null;
585   	try {
586 			fos = new FileOutputStream(file);
587 			byte[] bytes = contents.getBytes();
588 			fos.write(bytes);
589 		} catch (FileNotFoundException e) {
590 			logError(METHOD_NAME, e);
591 			throw new PlutoAdminException(e);
592 		} catch (IOException e) {
593 			logError(METHOD_NAME, e);
594 			throw new PlutoAdminException(e);
595 		}	finally {
596 			if (fos != null) {
597 				try {
598 					fos.close();
599 				} catch (IOException e) {
600 					logError(METHOD_NAME, e);
601 					throw new PlutoAdminException(e);
602 				}
603 			}
604 		}
605   }
606 
607 	  /***
608 	   * Updates web.xml with servlet and servlet-mapping records
609 	   * related to PortletServlet.
610 	   * 
611 	   * @param context
612 	   */
613 	  void updateWebXml(String context) {
614 		  String METHOD_NAME = "updateWebXml(context)";
615 		  //These constants are used to place the
616 		  //new record in web.xml in the proper place
617 		  	//elements to check prior to servlet (if not found)
618 		     final String[] PRIOR_ELEMENTS_SERVLET = 
619 		     	{"servlet", "listener", "filter-mapping", "filter", "context-param", 
620 		    		 "distributable", "description", "display-name", "icon", "web-app"};
621 			  	//elements to check prior to servlet-mapping  (if not found)
622 		     final String[] PRIOR_ELEMENTS_SERVLET_MAPPING = 
623 		     	{"servlet-mapping", "servlet"};
624 			String webapps = PlutoAdminContext.getDeploymentPath();
625 		     File webXml = new File(webapps + 
626 	 		 		 PlutoAdminConstants.FS + 
627 	 		 		 context + 
628 	 		 		 PlutoAdminConstants.FS + 
629 	 		 		 "WEB-INF" + 
630 	 		 		 PlutoAdminConstants.FS + 
631 	 		 		 "web.xml");
632 		     DeployWarService svc = new DeployWarService();
633 		     String contents = svc.readFileToString(webXml);
634 		     File portletXml = new File(webapps + 
635 	 		 		 PlutoAdminConstants.FS + 
636 	 		 		 context + 
637 	 		 		 PlutoAdminConstants.FS + 
638 	 		 		 "WEB-INF" + 
639 	 		 		 PlutoAdminConstants.FS + 
640 	 		 		 "portlet.xml");
641 			List plist = null;
642 			try {
643 				InputStream ins = new FileInputStream(portletXml);
644 			     PortletConfigService pcsvc = new PortletConfigService(ins);
645 			     plist = pcsvc.getPortletDDList();
646 			} catch (FileNotFoundException e) {
647 				logError(METHOD_NAME, e);
648 				throw new PlutoAdminException(e);
649 			}
650 			 String newWebXml = svc.addRecordsToWebXml(context, contents, 
651 					 PRIOR_ELEMENTS_SERVLET, plist); 
652 			 contents = newWebXml;
653 			 newWebXml = svc.addRecordsToWebXml(context, contents, 
654 					 PRIOR_ELEMENTS_SERVLET_MAPPING, plist); 
655 			 writeStringToFile(webXml, newWebXml);
656 		}
657 		  
658 	  
659 	  
660 	 /***
661 	  * Adds ServletPortlet servlet or servlet-mapping records to web.xml 
662 	  * for new portlet deployment.
663 	  * 
664 	  * @param context Web context or directory under webapps
665 	  * @param contents Current contents of the web.xml file
666 	  * @param elements Elements in web.xml to search for. If found, new
667 	  * elements will be inserted to the contents String. NOTE: First element
668 	  * (elements[0] signals the kind of record to add (servlet or servlet-mapping).
669 	  * @param portletData A List of PortletDD items containing the data of 
670 	  * portlets to be deployed.
671 	  */
672 		 String addRecordsToWebXml(String context, String contents, 
673 				 	String[] elements, List portletData ) {
674 			 String METHOD_NAME = "addRecordsToWebXml(context.contents,elements,portletData)";
675 			StringBuffer results = new StringBuffer(contents);
676 			 int index = -1;//index indicating the start of the insertion point
677 			 int len = portletData.size();
678 			 int lenElements = elements.length;
679 			 //string before a found element
680 			 String before = null;
681 			 //The new record to be added
682 			 String newRecord = null;
683 			 //The remainder of the string after the found element (tag)
684 			 String remainder = null;
685 			 //Rest of the string after the opening of the element
686 			 String rest = null;
687 			 //go through the list of portlets in ArrayLists 
688 			 for (int i = 0; i < len; i++) {
689 				 //check each element in web.xml contents
690 				 for (int j = 0; j < lenElements; j++) {
691 				     if ((index = results.lastIndexOf("</" + elements[j]+ ">")) != -1) {
692 					     //get the length to the end of the element (>)
693 				    	 rest = results.substring(index);
694 				    	 int elementLen = rest.indexOf('>') + 1;
695 				    	 //First portlet could have to deal with web-app element
696 				    	 //so the new records will be put after the web-app start element.
697 				    	 //Also account for web-app's attributes in calculating the element length
698 				    	 if (i == 0 & elements[j].equals("web-app")) {
699 							 index = results.indexOf("<web-app");
700 							 //Get the rest of the results String after <web-app
701 							 rest = results.substring(index);//get string starting with <web-app
702 							 elementLen = rest.indexOf('>') + 1;//end of starting web-app element
703 				    	 }
704 				    	 logDebug(METHOD_NAME, "Length of '" + elements[j] + "' tag = " + elementLen);
705 				    	 //get everything before the found element including the tag
706 				    	 before = results.substring(0, index + elementLen);
707 				    	 //get everything after the found element starting at the end of the tag
708 				    	 remainder = results.substring(index + elementLen);
709 				        //add the new element with child elements
710 				        //create the new element using the first item in the elements array
711 				        if (elements[0].equals("servlet")) {
712 				        	newRecord = getServletRecord(context, (PortletDD)portletData.get(i));
713 				        } else if (elements[0].equals("servlet-mapping")) {
714 				        	newRecord = getServletMappingRecord((PortletDD)portletData.get(i));
715 				        }
716 				        results = new StringBuffer();
717 				        results.append(before);
718 				        //start the new content with a newline
719 				        results.append(PlutoAdminConstants.LS);
720 				        results.append(newRecord);
721 				        results.append(remainder);
722 				        break;
723 				     }
724 				 }
725 			 }
726 			 return results.toString();
727 		
728 		}
729 
730 		/***
731 	    * Gets the web.xml servlet record for PortletServlet
732 	    * from portlet.xml data
733 	    * 
734 	    * @param context Context name
735 	    * @param portletData Data from portlet.xml
736 	    * @return
737 	    */
738 		 private String getServletRecord(String context, PortletDD portletData) {
739 		     
740 		     StringBuffer record = new StringBuffer();
741 		     
742 		     record.append("    <servlet>" + PlutoAdminConstants.LS);
743 		     record.append("      <servlet-name>" + portletData.getPortletName() + "</servlet-name>" + PlutoAdminConstants.LS);
744 		     record.append("      <display-name>" + portletData.getPortletName() + " Wrapper</display-name>" + PlutoAdminConstants.LS);
745 		     record.append("      <description>Automated generated Portlet Wrapper</description>" + PlutoAdminConstants.LS);
746 		     record.append("      <servlet-class>org.apache.pluto.core.PortletServlet</servlet-class>" + PlutoAdminConstants.LS);
747 		     record.append("      <init-param>" + PlutoAdminConstants.LS);
748 		     record.append("        <param-name>portlet-guid</param-name>" + PlutoAdminConstants.LS);
749 		     record.append("        <param-value>" + context + "." + portletData.getPortletName() + "</param-value>" + PlutoAdminConstants.LS);
750 		     record.append("      </init-param>" + PlutoAdminConstants.LS);
751 		     record.append("      <init-param>" + PlutoAdminConstants.LS);
752 		     record.append("        <param-name>portlet-class</param-name>" + PlutoAdminConstants.LS);
753 		     record.append("        <param-value>" + portletData.getPortletClass() + "</param-value>" + PlutoAdminConstants.LS);
754 		     record.append("      </init-param>" + PlutoAdminConstants.LS);
755 		     //Add list of security-role-ref elements with 
756 		     // corresponding role-name and role-link if there is one in portlet.xml
757 		     String securityRef = getSecurityRoleRefRecord(context, portletData);
758 		     if (securityRef != null && !securityRef.equals("")) {
759 		    	 record.append(securityRef);
760 		     }
761 		     record.append("    </servlet>" + PlutoAdminConstants.LS);
762 		  
763 		     return record.toString();
764 		 }
765 
766 			/***
767 		    * Gets the web.xml security-role-ref record for PortletServlet
768 		    * from portlet.xml data
769 		    * 
770 		    * @param context Context name
771 		    * @param portletData Data from portlet.xml
772 		    * @return
773 		    */
774 			 private String getSecurityRoleRefRecord(String context, PortletDD portletData) {
775 			     
776 			     StringBuffer record = new StringBuffer("");
777 			     
778 			     List refs = portletData.getSecurityRoleRefs();
779 			     String link = null;
780 			     for (Iterator iter = refs.iterator(); iter.hasNext();) {
781 			    	 PortletConfigService.RoleRef ref = (PortletConfigService.RoleRef) iter.next();
782 				     record.append("      <security-role-ref>" + PlutoAdminConstants.LS);
783 				     record.append("        <role-name>"+ ref.roleName + "</role-name>" + PlutoAdminConstants.LS);
784 				     //role-link is optional
785 				     link = ref.roleLink;
786 				     if (link != null && !link.equals("")) {
787 				    	 record.append("        <role-link>" + link + "</role-link>" + PlutoAdminConstants.LS);
788 				     }
789 				     record.append("      </security-role-ref>" + PlutoAdminConstants.LS);
790 				 } 
791 			  
792 			     return record.toString();
793 			 }
794 
795 	  /***
796 	    * Gets the web.xml servlet-mapping record for PortletServlet
797 	    * from portlet.xml data
798 	    * 
799 	    * @param context Context name
800 	    * @param portletData Data from portlet.xml
801 	    * @return
802 	    */
803 	   private String getServletMappingRecord(PortletDD portletData) {
804 	       
805 	       StringBuffer record = new StringBuffer();
806 	       
807 	       record.append("    <servlet-mapping>" + PlutoAdminConstants.LS);
808 	       record.append("      <servlet-name>" + portletData.getPortletName() + "</servlet-name>" + PlutoAdminConstants.LS);
809 	       //pattern = /PortletName/*
810 	       record.append("      <url-pattern>/" + portletData.getPortletName() + "/*</url-pattern>" + PlutoAdminConstants.LS);
811 	       record.append("    </servlet-mapping>" + PlutoAdminConstants.LS);
812 	    
813 	       return record.toString();
814 	   }
815 
816 }