Project: dolphin
package com.sysdeo.eclipse.tomcat;
 
/*
 * (c) Copyright Sysdeo SA 2001, 2002. 
 * All Rights Reserved. 
 */
 
  
import java.io.ByteArrayInputStream; 
import java.io.File; 
import java.io.IOException; 
import java.net.URLDecoder; 
import java.net.URLEncoder; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import java.util.StringTokenizer; 
 
import org.eclipse.core.resources.IFile; 
import org.eclipse.core.resources.IFolder; 
import org.eclipse.core.resources.IProject; 
import org.eclipse.core.resources.IProjectNature; 
import org.eclipse.core.resources.IResource; 
import org.eclipse.core.resources.IResourceStatus; 
import org.eclipse.core.resources.ResourcesPlugin; 
import org.eclipse.core.runtime.CoreException; 
import org.eclipse.core.runtime.IPath; 
import org.eclipse.core.runtime.IStatus; 
import org.eclipse.core.runtime.PlatformObject; 
import org.eclipse.core.runtime.QualifiedName; 
import org.eclipse.core.runtime.Status; 
import org.eclipse.jdt.core.IClasspathEntry; 
import org.eclipse.jdt.core.IJavaProject; 
import org.eclipse.jdt.core.JavaCore; 
 
import com.sysdeo.eclipse.tomcat.editors.ProjectListElement; 
 
 
 
 
public class TomcatProject extends PlatformObject implements IProjectNature  { 
 
 // Persistence properties of projects 
 private static final String PROPERTIES_FILENAME = ".tomcatplugin"
 private static final String KEY_WEBPATH = "webPath"
 private static final String KEY_UPDATEXML = "updateXml"
 private static final String KEY_EXPORTSOURCE = "exportSource"
 private static final String KEY_RELOADABLE="reloadable"
 private static final String KEY_REDIRECTLOGGER="redirectLogger";  
 private static final String KEY_WARLOCATION = "warLocation"
 private static final String KEY_ROOTDIR = "rootDir"
 private static final String KEY_EXTRAINFO = "extraInfo"
 private static final String KEY_WEBCLASSPATH = WebClassPathEntries.TAG_NAME; 
 private static final String extraBeginTag = "<!-- Extra info begin -->"
 private static final String extraEndTag = "<!-- Extra info end -->";  
 
// private static final QualifiedName QN_WEBPATH = new QualifiedName("TomcatProject", KEY_WEBPATH); 
// private static final QualifiedName QN_UPDATEXML = new QualifiedName("TomcatProject", KEY_UPDATEXML); 
// private static final QualifiedName QN_EXPORTSOURCE = new QualifiedName("TomcatProject", KEY_EXPORTSOURCE); 
// private static final QualifiedName QN_RELOADABLE = new QualifiedName("TomcatProject", KEY_RELOADABLE); 
// private static final QualifiedName QN_REDIRECTLOGGER = new QualifiedName("TomcatProject", KEY_REDIRECTLOGGER); 
// private static final QualifiedName QN_WARLOCATION = new QualifiedName("TomcatProject", KEY_WARLOCATION); 
// private static final QualifiedName QN_ROOTDIR = new QualifiedName("TomcatProject", KEY_ROOTDIR); 
 
 
 /**
  * The platform project this <code>TomcatProject</code> is based on 
  */
 
 protected IProject project; 
 protected IJavaProject javaProject; 
 
 protected String webPath = ""
 protected String warLocation = ""
 protected String rootDir = ""
 protected String extraInfo = ""
 protected boolean updateXml; 
 protected boolean exportSource; 
 protected boolean reloadable = true
 protected boolean redirectLogger = false
 protected WebClassPathEntries webClassPathEntries; 
  
 protected IFolder rootDirFolder; 
 
 /**
  * Gets the project. 
  * @return Returns a IProject 
  */
 
 public IProject getProject() { 
  return project; 
 
 
 /**
  * Sets the project. 
  * @param project The project to set 
  */
 
 public void setProject(IProject project) { 
  this.project = project; 
 
  
 /*
  * @see IProjectNature#configure() 
  */
 
 public void configure() throws CoreException { 
 
 
 /*
  * @see IProjectNature#deconfigure() 
  */
 
 public void deconfigure() throws CoreException { 
 
 
 /*
  * @see IProjectNature#getProject() 
  */
 
 public IJavaProject getJavaProject() { 
  return javaProject; 
 
 
 /*
  * @see IProjectNature#setProject(IProject) 
  */
 
 public void setJavaProject(IJavaProject javaProject) { 
  this.javaProject = javaProject; 
  this.setProject(javaProject.getProject()); 
 
 
 
 static public void addTomcatNature(IJavaProject project) { 
  try { 
   JDTUtil.addNatureToProject(project.getProject(), TomcatLauncherPlugin.NATURE_ID);   
  catch(CoreException ex) { 
   TomcatLauncherPlugin.log(ex.getMessage()); 
  
 
 
 static public void removeTomcatNature(IJavaProject project) { 
  try { 
   JDTUtil.removeNatureToProject(project.getProject(), TomcatLauncherPlugin.NATURE_ID);   
  catch(CoreException ex) { 
   TomcatLauncherPlugin.log(ex.getMessage()); 
  
 
 
 /**
  * Return a TomcatProject if this javaProject has the tomcat nature 
  * Return null if Project has not tomcat nature 
  */
 
 static public TomcatProject create(IJavaProject javaProject) { 
  TomcatProject result = null
  try { 
   result = (TomcatProject)javaProject.getProject().getNature(TomcatLauncherPlugin.NATURE_ID); 
   if(result != null
    result.setJavaProject(javaProject); 
  catch(CoreException ex) { 
   TomcatLauncherPlugin.log(ex.getMessage()); 
  
  return result; 
 
 
 /**
  * Return a TomcatProject if this Project has the tomcat nature 
  * Return null if Project has not tomcat nature 
  */
 
 static public TomcatProject create(IProject project) { 
 
  IJavaProject javaProject = JavaCore.create(project); 
  if(javaProject != null) { 
   return TomcatProject.create(javaProject); 
  else { 
   return null
  
 }  
 
 private File getPropertiesFile() { 
  return (this.getProject().getLocation().append(PROPERTIES_FILENAME).toFile()); 
 
  
 private String readProperty(String key) { 
  String result = null
  try { 
   result = FileUtil.readPropertyInXMLFile(getPropertiesFile(), key); 
  catch (IOException e) { 
   try { 
    result = getJavaProject().getCorrespondingResource().getPersistentProperty(new QualifiedName("TomcatProject", key)); 
   catch (Exception e2) { 
    TomcatLauncherPlugin.log(e2); 
   
  
   
  if(result == null) { 
   result = ""
  
    
  return result; 
 
  
 /**
  * Gets the rootDir. 
  * @return Returns a String 
  */
 
 public String getRootDir() { 
  return this.readProperty(KEY_ROOTDIR); 
 }  
 
 /**
  * Sets the rootDir. 
  * @param rootDir The rootDir to set 
  */
 
 public void setRootDir(String rd) { 
  this.rootDir = rd; 
  this.rootDirFolder = null
 
   
 /**
  * Gets the webpath. 
  * @return Returns a String 
  */
 
 public String getWebPath() { 
  return this.readProperty(KEY_WEBPATH); 
 }  
 
 /**
  * Sets the webpath. 
  * @param webpath The webpath to set 
  */
 
 public void setWebPath(String wp) { 
  this.webPath = wp; 
 
 
 public void updateWebPath(String newWebPath) throws Exception { 
  setWebPath(newWebPath);  
  if(!newWebPath.equals(this.getWebPath())) { 
   if(getUpdateXml()) { 
    removeContext(); 
   
  }  
 
   
 /**
  * Gets the warfile. 
  * @return Returns a String 
  */
 
 public String getWarLocation() { 
  return this.readProperty(KEY_WARLOCATION); 
 
 
 /**
  * Sets the warfile 
  * @param warfile The warfile to set 
  */
 
 public void setWarLocation(String wl) { 
  this.warLocation = wl; 
 
  
 /**
  * Gets the updateXml. 
  * @return Returns a boolean 
  */
 
 public boolean getUpdateXml() { 
  return new Boolean(this.readProperty(KEY_UPDATEXML)).booleanValue(); 
 
 
 /**
  * Sets the updateXml. 
  * @param updateXml The updateXml to set 
  */
 
 public void setUpdateXml(boolean updateXml) { 
  this.updateXml = updateXml; 
 
 
 /**
  * Gets the updateXml. 
  * @return Returns a boolean 
  */
 
 public boolean getExportSource() { 
  return new Boolean(this.readProperty(KEY_EXPORTSOURCE)).booleanValue(); 
 
 
 /**
  * Sets the exportSource. 
  * @param exportSource The exportSource to set 
  */
 
 public void setExportSource(boolean exportSource) { 
  this.exportSource = exportSource; 
 
 
 /**
  * Gets the reloadable 
  * @return Returns a boolean 
  */
 
 public boolean getReloadable(){ 
  String reloadableProperty = this.readProperty(KEY_RELOADABLE); 
  // Set default value to true 
  if(reloadableProperty.equals("")) { 
   reloadableProperty = "true";  
  
  return new Boolean(reloadableProperty).booleanValue(); 
 
  
 /**
  * Sets the reloadable 
  * @param reloadable The reloadable to set 
  */
 
 public void setReloadable(boolean reloadable){ 
  this.reloadable = reloadable; 
 
 
 /**
  * Gets the reloadable 
  * @return Returns a boolean 
  */
 
 public boolean getRedirectLogger(){ 
  String redirectLoggerProperty = this.readProperty(KEY_REDIRECTLOGGER); 
  // Set default value to false 
  if(redirectLoggerProperty.equals("")) { 
   redirectLoggerProperty = "false";  
  
  return new Boolean(redirectLoggerProperty).booleanValue(); 
 
  
 /**
  * Sets the reloadable 
  * @param reloadable The reloadable to set 
  */
 
 public void setRedirectLogger(boolean redirectLogger){ 
  this.redirectLogger = redirectLogger; 
 
 
 /**
  * Gets the warfile. 
  * @return Returns a String 
  */
 
 public String getExtraInfo() { 
  return URLDecoder.decode(this.readProperty(KEY_EXTRAINFO)); 
 
 
 /**
  * Sets the warfile 
  * @param warfile The warfile to set 
  */
 
 public void setExtraInfo(String extra) { 
  this.extraInfo = extra; 
 
   
 /**
  * set the classpath entries which shall be loaded by the webclassloader 
  * @param entries List of WebClasspathEntry objects 
  */
 
 public void setWebClassPathEntries(WebClassPathEntries entries) { 
  webClassPathEntries = entries; 
 
  
 /** 
  * return the webclasspath entries 
  */
 
 public WebClassPathEntries getWebClassPathEntries() { 
  try { 
   return WebClassPathEntries.xmlUnmarshal(FileUtil.readTextFile(getPropertiesFile())); 
  catch(IOException ioEx) { 
   return null
  
 
 
 /*
  * Store exportSource in project persistent properties 
  */
 
 public void saveProperties() { 
  try { 
   StringBuffer fileContent = new StringBuffer(); 
   fileContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 
   fileContent.append("<tomcatProjectProperties>\n"); 
   fileContent.append("    <rootDir>" + rootDir + "</rootDir>\n"); 
   fileContent.append("    <exportSource>" + exportSource + "</exportSource>\n"); 
   fileContent.append("    <reloadable>" + reloadable + "</reloadable>\n"); 
   fileContent.append("    <redirectLogger>" + redirectLogger + "</redirectLogger>\n"); 
   fileContent.append("    <updateXml>" + updateXml + "</updateXml>\n"); 
   fileContent.append("    <warLocation>" + warLocation + "</warLocation>\n"); 
   fileContent.append("    <extraInfo>" + URLEncoder.encode(extraInfo) + "</extraInfo>\n");    
   fileContent.append("    <webPath>" + webPath + "</webPath>\n");   
   if (webClassPathEntries != null) { 
    fileContent.append(webClassPathEntries.xmlMarshal(4)); 
   
   fileContent.append("</tomcatProjectProperties>\n"); 
   FileUtil.toTextFile(getPropertiesFile(), fileContent.toString()); 
   // refresh the project files.  
   project.refreshLocal(IResource.DEPTH_ONE, null);  
    
   //Notification for VCM (Team plug-in) 
   IFile propertiesIFile = this.getProject().getFile(PROPERTIES_FILENAME); 
   ResourcesPlugin.getWorkspace().validateEdit(new IFile[]{propertiesIFile}, null); 
    
    
  catch (Exception ex) { 
   TomcatLauncherPlugin.log(ex.getMessage());  
  }  
 
 
 /**
  * Run all the steps to configure a JavaProject as a TomcatProject 
  */
 
 public void fullConfiguration() throws CoreException, IOException { 
  if(!rootDir.equals("")) { 
   this.initRootDirFolder(true);  
  
 
  this.addProjectToSourcePathPref();  
  this.createWEBINFFolder(); 
  this.createWEBINFSrcFolder(); 
  this.createWorkFolder(); 
   
  this.addTomcatJarToProjectClasspath(); 
  this.addWEBINFLibJarFilesToProjectClasspath(); 
     
  this.clearDefaultSourceEntries(); 
  this.setClassesAsOutputFolder(); 
  if(classesContainsJavaFiles()) { 
   this.setClassesAsSourceFolder(); 
  
   
  this.setSrcAsSourceFolder(); 
  this.setWEBINFSrcAsSourceFolder(); 
  this.setWorkAsSourceFolder(); 
  
  this.updateContext(); 
 
 
 public void clearDefaultSourceEntries()  throws CoreException { 
  IClasspathEntry[] entries = javaProject.getRawClasspath(); 
  List cp= new ArrayList(entries.length + 1); 
  for(int i=0; i<entries.length; i++) { 
   if(entries[i].getEntryKind() != IClasspathEntry.CPE_SOURCE) { 
    cp.add(entries[i]); 
   
  
  javaProject.setRawClasspath((IClasspathEntry[])cp.toArray(new IClasspathEntry[cp.size()]), null); 
 
 
 /*
  * Add servlet.jar and jasper.jar to project classpath 
  */
  
 public void addTomcatJarToProjectClasspath()  throws CoreException { 
  TomcatBootstrap tb = TomcatLauncherPlugin.getDefault().getTomcatBootstrap(); 
   
  IClasspathEntry[] entries = javaProject.getRawClasspath(); 
  List cp = new ArrayList(entries.length + 1); 
   
  for (int i = 0; i < entries.length; i++) { 
   IClasspathEntry entry = entries[i]; 
   if(!((entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) &&  
    (entry.getPath().toOSString().startsWith(TomcatLauncherPlugin.getDefault().getTomcatIPath().toOSString())))) { 
    cp.add(entry); 
   }   
  
 
  cp.addAll(tb.getTomcatJars()); 
        
  javaProject.setRawClasspath((IClasspathEntry[])cp.toArray(new IClasspathEntry[cp.size()]), null); 
 
  
 
 /*
  * Add all jar in WEB-INF/lib to project classpath 
  */
 
 public void addWEBINFLibJarFilesToProjectClasspath()  throws CoreException { 
  IFolder libFolder = this.getWebInfFolder().getFolder("lib"); 
  IResource[] libFiles = libFolder.members(); 
 
  IClasspathEntry[] entries = javaProject.getRawClasspath(); 
  List cp= new ArrayList(entries.length + 1); 
  cp.addAll(Arrays.asList(entries)); 
   
  for(int i=0; i<libFiles.length; i++) { 
   if((libFiles[i].getType() == IResource.FILE) && (libFiles[i].getFileExtension().equalsIgnoreCase("jar"))) { 
    cp.add(JavaCore.newLibraryEntry(libFiles[i].getFullPath(), nullnull)); 
   }     
  
 
  javaProject.setRawClasspath((IClasspathEntry[])cp.toArray(new IClasspathEntry[cp.size()]), null); 
 
  
 public IFolder getWebInfFolder() { 
  if (getRootDirFolder() == null) { 
   return project.getFolder("WEB-INF"); 
  else { 
   return getRootDirFolder().getFolder("WEB-INF"); 
  
 
 
 public IFolder getWorkFolder() { 
//  if (getRootDirFolder() == null) { 
//   return project.getFolder("work"); 
//  } else { 
//   return getRootDirFolder().getFolder("work"); 
//  } 
 
  return project.getFolder("work"); 
   
 
 
 public IFolder getRootDirFolder() { 
  if (rootDirFolder == null) { 
   this.initRootDirFolder(false); 
  
  return rootDirFolder; 
 
 
 private void initRootDirFolder(boolean create) { 
  StringTokenizer tokenizer = new StringTokenizer(this.getRootDir(), "/\\:"); 
  IFolder folder = null
  try { 
   while (tokenizer.hasMoreTokens()) { 
    String each = tokenizer.nextToken(); 
    if (folder == null) { 
     folder = project.getFolder(each); 
    else { 
     folder = folder.getFolder(each); 
    
    if (create) { 
     this.createFolder(folder); 
    
   
  catch (CoreException ex) { 
   TomcatLauncherPlugin.log(ex); 
   folder = null
   setRootDir("/"); 
  
  this.rootDirFolder = folder; 
 
 
 
 
 public void createWEBINFFolder()  throws CoreException { 
  IFolder webinfFolder = this.getWebInfFolder();  
  this.createFolder(webinfFolder); 
  this.createFolder(webinfFolder.getFolder("classes")); 
  this.createFolder(webinfFolder.getFolder("lib")); 
      
  // Create .cvsignore for classes 
  this.createFile(webinfFolder.getFile(".cvsignore"), "classes");      
 
 
 public void createWEBINFSrcFolder()  throws CoreException { 
  this.createFolder(this.getWebInfFolder().getFolder("src")); 
 
 
 public void createWorkFolder()  throws CoreException { 
  IFolder folderHandle = this.getWorkFolder(); 
  this.createFolder(folderHandle); 
   
  String tomcatVersion = TomcatLauncherPlugin.getDefault().getTomcatVersion(); 
  if(tomcatVersion.equals(TomcatLauncherPlugin.TOMCAT_VERSION4)  
    || tomcatVersion.equals(TomcatLauncherPlugin.TOMCAT_VERSION41)) {   
   folderHandle = folderHandle.getFolder("org"); 
   this.createFolder(folderHandle); 
   folderHandle = folderHandle.getFolder("apache"); 
   this.createFolder(folderHandle); 
   folderHandle = folderHandle.getFolder("jsp"); 
   this.createFolder(folderHandle); 
  
   
  // Add a .cvsignore file in work directory 
  this.createFile(project.getFile(".cvsignore") , "work");      
      
 
 
 public void setSrcAsSourceFolder()  throws CoreException { 
//  this.setFolderAsSourceEntry(project.getFolder("src")); 
 
 
 public void setWEBINFSrcAsSourceFolder()  throws CoreException { 
  this.setFolderAsSourceEntry(this.getWebInfFolder().getFolder("src"), null); 
 
 
 
 public void setClassesAsOutputFolder()  throws CoreException { 
  IFolder classesFolder = this.getWebInfFolder().getFolder("classes"); 
  javaProject.setOutputLocation(classesFolder.getFullPath(),null); 
 
 
 public void setClassesAsSourceFolder()  throws CoreException {  
  IFolder classesFolder = this.getWebInfFolder().getFolder("classes"); 
  this.setFolderAsSourceEntry(classesFolder, null); 
 
  
 public void setWorkAsSourceFolder()  throws CoreException { 
  this.setFolderAsSourceEntry(this.getWorkFolder(), this.getWorkFolder()); 
 
 
 
 private void createFolder(IFolder folderHandle)  throws CoreException {   
  try { 
   // Create the folder resource in the workspace 
   folderHandle.create(falsetruenull); //new SubProgressMonitor(monitor, 500)); 
  
  catch (CoreException e) { 
   // If the folder already existed locally, just refresh to get contents 
   if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) 
    folderHandle.refreshLocal(IResource.DEPTH_INFINITE, null); //new SubProgressMonitor(monitor, 500)); 
   else 
    throw e; 
  
 
 
 private void createFile(IFile fileHandle, String content)  throws CoreException {      
  try { 
   fileHandle.create(new ByteArrayInputStream(content.getBytes()), 0null); 
  
  catch (CoreException e) { 
   // If the file already existed locally, just refresh to get contents 
   if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) 
    fileHandle.refreshLocal(IResource.DEPTH_INFINITE, null); //new SubProgressMonitor(monitor, 500)); 
   else 
    throw e; 
  
 
   
   
 /*
  * ouput could be null (project default output will be used) 
  */
 
 private void setFolderAsSourceEntry(IFolder folderHandle, IFolder output) throws CoreException { 
  IClasspathEntry[] entries= javaProject.getRawClasspath(); 
  IClasspathEntry[] newEntries= new IClasspathEntry[entries.length + 1]; 
  System.arraycopy(entries,0, newEntries,0, entries.length); 
  IPath outputPath = null
  if(output != null) outputPath = output.getFullPath(); 
   
  IPath[] emptyPath = {}; 
  newEntries[entries.length] = JavaCore.newSourceEntry(folderHandle.getFullPath(), emptyPath, outputPath); 
 
  javaProject.setRawClasspath(newEntries, null);  
 
 
   
 /**
  * Add or update a Context definition 
  */
 
 public void updateContext() throws CoreException, IOException { 
  if(TomcatLauncherPlugin.getDefault().getConfigMode().equals(TomcatLauncherPlugin.SERVERXML_MODE)) { 
   this.updateServerXML(); 
  else { 
   this.updateContextFile(); 
  
 
  
 /*
  * Add or update a Context entry on Tomcat server.xml file 
  */
 
 private void updateServerXML() throws CoreException, IOException { 
 
  if(getUpdateXml()) {   
   this.backupServerXML(); 
 
   String xml = FileUtil.readTextFile(getServerXML()); 
   if(!contextExistsInXML(xml)) { 
    this.addContextToServerXML();  
   else { 
    this.updateContextDefinitionInFile(getServerXML());   
   
  
 }  
 
 /*
  * create or update a Context file 
  */
 
 private void updateContextFile() throws CoreException, IOException { 
 
  if(getUpdateXml()) { 
   File contextFile = this.getContextFile(); 
   if(!contextFile.exists()) { 
    FileUtil.toTextFile(contextFile, this.createContextDefinition());  
   else { 
    updateContextDefinitionInFile(contextFile); 
   
  
 
 
 
 private File getContextFile() { 
  File contextFile = new File(TomcatLauncherPlugin.getDefault().getContextsDir() + 
   File.separator + getContextFileName()); 
  return contextFile; 
 
  
 private String getContextFileName() { 
  String contextFileName = this.getWebPath(); 
  if(contextFileName.startsWith("/")) { 
   contextFileName = contextFileName.substring(1); 
  
   
  // Tomcat 5 converts / to # in context file name 
  contextFileName = contextFileName.replace('/', '#'); 
   
  return contextFileName + ".xml";  
 
  
  
  
 public void removeContext() throws CoreException, IOException { 
  // Always call removeContext file because Tomcat create it automatically when using server.xml 
  this.removeContextFile(); 
   
  if(TomcatLauncherPlugin.getDefault().getConfigMode().equals(TomcatLauncherPlugin.SERVERXML_MODE)) { 
   this.removeContextInServerXML(); 
  
 
 
 private void removeContextFile() { 
  this.getContextFile().delete();  
 
  
 private void removeContextInServerXML() throws CoreException, IOException { 
  this.backupServerXML(); 
 
  String xml = FileUtil.readTextFile(getServerXML()); 
  if(contextExistsInXML(xml)) {    
   int contextTagIdx = this.getContextTagIndex(xml);    
   int endTagIndex = xml.indexOf("</Context>", contextTagIdx); 
   boolean hasNoBody = false
   if (endTagIndex < 0) { 
    endTagIndex = xml.indexOf('>', contextTagIdx); 
    hasNoBody = true
   
   else 
    endTagIndex+= "</Context>".length(); 
    
 
   StringBuffer out = null
 
   out = new StringBuffer(xml.substring(0, contextTagIdx)); 
   out.append(xml.substring(endTagIndex+1, xml.length()));     
 
   if (out != null) FileUtil.toTextFile(getServerXML(), out.toString());     
     
  
 
 
 
 /**
  * Backup Tomcat server.xml file using the following algorithm : 
  * - Initial server.xml is backuped to server.xml.backup 
  * - Before updating server.xml create a copy named server.xml.old 
  */
 
 public void backupServerXML() throws CoreException, IOException { 
  String backup =  getServerXMLLocation() + ".backup"
  String old =  getServerXMLLocation() + ".old"
    
  if(!getServerXML().exists()) { 
   String msg = "Tomcat server.xml file is not found in " + getServerXML().getAbsolutePath(); 
   Status status = new Status(IStatus.ERROR, TomcatLauncherPlugin.getDefault().getDescriptor().getUniqueIdentifier(), IStatus.ERROR, msg, null); 
   throw new CoreException(status); 
  
    
  File backupFile = new File(backup); 
  if(!backupFile.exists()) { 
   FileUtil.copy(getServerXML(), backupFile);  
  
   
  FileUtil.copy(getServerXML(), new File(old));    
 
  
 
  
 private File getServerXML() { 
  return new File(getServerXMLLocation());   
 
  
 private String getServerXMLLocation() { 
  return TomcatLauncherPlugin.getDefault().getConfigFile(); 
 
 
 
 /**
  * Quick and dirty implementations : using an XML Parser would be better 
  */
 
 private boolean contextExistsInXML(String xml) throws IOException { 
  return (getContextTagIndex(xml) != -1); 
 
  
 private int getContextTagIndex(String xml) throws IOException { 
  int pathIndex = xml.indexOf(getContextPath()); 
   
  if(pathIndex == -1
   return -1;   
   
  int tagIndex = (xml.substring(0, pathIndex)).lastIndexOf('<'); 
  String tag = xml.substring(tagIndex, tagIndex + 8);  
  if(!tag.equalsIgnoreCase(getContextStartTag())) 
   return -1
    
  return tagIndex; 
 
  
 private void addContextToServerXML() throws IOException { 
  String xml = FileUtil.readTextFile(getServerXML()); 
  String tag = TomcatLauncherPlugin.getDefault().getTomcatBootstrap().getXMLTagAfterContextDefinition(); 
    
  int tagIndex = xml.indexOf(tag); 
  int insertIndex = (xml.substring(0, tagIndex)).lastIndexOf('\n'); 
    
  StringBuffer out = new StringBuffer(xml.substring(0, insertIndex)); 
  out.append(this.createContextDefinition()); 
  out.append(xml.substring(insertIndex, xml.length())); 
   
  FileUtil.toTextFile(getServerXML(), out.toString());  
 
  
 private String createContextDefinition() { 
  StringBuffer contextBuffer = new StringBuffer(); 
  contextBuffer.append(getContextStartTag()); 
  contextBuffer.append(' '); 
  contextBuffer.append(getContextPath()); 
  contextBuffer.append(' '); 
  contextBuffer.append(getContextReloadable());  
  contextBuffer.append(' ');   
  contextBuffer.append(getContextDocBase()); 
  contextBuffer.append(' '); 
  contextBuffer.append(getContextWorkDir()); 
  contextBuffer.append(" />\n"); 
 
  String context = contextBuffer.toString();    
  if (getWebClassPathEntries() != null) { 
   context = this.addLoaderToContext(context); 
  
  if(getRedirectLogger()) { 
   context = this.addLoggerToContext(context); 
  
  if(!(getExtraInfo().equals(""))) { 
   context = this.addExtraInfoToContext(context); 
  
   
  return context; 
  
 
 
 private String updateContextDefinition(String context) { 
 
  // if reloadable param not set 
  int reloadableIndex = context.indexOf("reloadable"); 
  if(reloadableIndex == -1) { 
   context = this.addReloadableToContext(context); 
  else { 
   context = this.updateReloadableInContext(context); 
  
     
  // update docBase if set 
  int docBaseIndex = context.indexOf("docBase"); 
  if(docBaseIndex == -1) { 
   context = this.addDocBaseToContext(context); 
  else { 
   context = this.updateDocBaseInContext(context); 
  }  
 
  // if work param not set 
  int workIndex = context.indexOf("workDir"); 
  if(workIndex == -1) { 
   context = this.addWorkToContext(context); 
  else { 
   context = this.updateWorkInContext(context); 
  
 
  // if loader not set 
  int loaderIndex = context.indexOf("<Loader"); 
  if((loaderIndex == -1) && (getWebClassPathEntries() != null)) { 
   context = this.addLoaderToContext(context); 
  
  if((loaderIndex != -1) && (getWebClassPathEntries() == null)) { 
   context = this.removeLoaderInContext(context); 
  }   
  if((loaderIndex != -1) && (getWebClassPathEntries() != null)) { 
   context = this.updateLoaderInContext(context); 
  }   
  
 
  // if logger not set 
  int loggerIndex = context.indexOf("<Logger"); 
  if((loggerIndex == -1) && getRedirectLogger()) { 
   context = this.addLoggerToContext(context); 
  
  if((loggerIndex != -1) && !getRedirectLogger()) { 
   context = this.removeLoggerInContext(context); 
  }   
  if((loggerIndex != -1) && getRedirectLogger()) { 
   context = this.updateLoggerInContext(context); 
  
   
  // Extra info 
  int extraInfoIndex = context.indexOf(extraBeginTag); 
  if((extraInfoIndex == -1) && !(getExtraInfo().equals(""))) { 
   context = this.addExtraInfoToContext(context); 
  
  if((extraInfoIndex != -1) && getExtraInfo().equals("")) { 
   context = this.removeExtraInfoInContext(context); 
  }   
  if((extraInfoIndex != -1) && !(getExtraInfo().equals(""))) { 
   context = this.updateExtraInfoInContext(context); 
  
  return context; 
 
  
 private void updateContextDefinitionInFile(File xmlFile) throws IOException { 
  String xml = FileUtil.readTextFile(xmlFile);  
  int contextTagIndex = this.getContextTagIndex(xml); 
   
  // If context doesn't exist do nothing 
  if( contextTagIndex == -1) { 
   return
  }    
 
  // Get context      
  int endContextTagIndex = xml.indexOf(">",contextTagIndex); 
  if(xml.charAt(endContextTagIndex-1) != '/') { 
   endContextTagIndex = xml.indexOf(this.getContextEndTag(), contextTagIndex) + this.getContextEndTag().length() -1  
  
  String context = xml.substring(contextTagIndex, endContextTagIndex+1); 
 
  StringBuffer out = new StringBuffer(xml.substring(0, contextTagIndex)); 
  out.append(this.updateContextDefinition(context)); 
  out.append(xml.substring(endContextTagIndex+1)); 
  FileUtil.toTextFile(xmlFile, out.toString());  
 
 
 
 private String addDocBaseToContext(String context) { 
  int reloadableIndex = context.indexOf(getContextReloadable()); 
  int firstDoubleQuoteIndex = context.indexOf('"', reloadableIndex) + 1;   
  int docBaseIndex = context.indexOf('"',firstDoubleQuoteIndex) + 1
  StringBuffer out = new StringBuffer(context.substring(0, docBaseIndex)); 
  out.append(' '); 
  out.append(getContextDocBase()); 
  out.append(' '); 
  out.append(context.substring(docBaseIndex, context.length()));     
   
  return out.toString();    
 
 
 private String updateDocBaseInContext(String context) { 
  int docBaseIndex = context.indexOf("docBase"); 
  int startIndex = context.indexOf('"', docBaseIndex); 
  int endIndex = context.indexOf('"',startIndex+1); 
  StringBuffer out = new StringBuffer(context.substring(0, docBaseIndex)); 
  out.append(getContextDocBase()); 
  out.append(context.substring(endIndex+1, context.length())); 
   
  return out.toString();    
 
 
 private String getContextReloadable(){ 
  return ("reloadable=" + '"' + getReloadable() + '"'); 
 
 
 private String addReloadableToContext(String context) { 
  int pathIndex = context.indexOf(getContextPath()); 
  int firstDoubleQuoteIndex = context.indexOf('"', pathIndex) + 1
  int reloadableIndex = context.indexOf('"',firstDoubleQuoteIndex) + 1
   
  StringBuffer out = new StringBuffer(context.substring(0, reloadableIndex)); 
  out.append(' '); 
  out.append(getContextReloadable()); 
  out.append(' '); 
  out.append(context.substring(reloadableIndex, context.length()));     
   
  return out.toString();    
 
 
 private String updateReloadableInContext(String context){ 
  int reloadableIndex = context.indexOf("reloadable"); 
  int startIndex = context.indexOf('"',reloadableIndex); 
  int endIndex = context.indexOf('"',startIndex+1); 
  StringBuffer out = new StringBuffer(context.substring(0,reloadableIndex)); 
  out.append(getContextReloadable()); 
  out.append(context.substring(endIndex+1,context.length())); 
   
  return out.toString(); 
 
  
 private String addWorkToContext(String context) { 
  int docBaseIndex = context.indexOf("docBase"); 
  int firstDoubleQuoteIndex = context.indexOf('"',docBaseIndex) + 1
  int workIndex = context.indexOf('"', firstDoubleQuoteIndex) + 1
  StringBuffer out = new StringBuffer(context.substring(0, workIndex)); 
  out.append(' '); 
  out.append(getContextWorkDir()); 
  out.append(' '); 
  out.append(context.substring(workIndex, context.length()));     
   
  return out.toString();    
 
 
 private String updateWorkInContext(String context) { 
  int workDirIndex = context.indexOf("workDir"); 
  int startIndex = context.indexOf('"', workDirIndex); 
  int endIndex = context.indexOf('"',startIndex+1); 
  StringBuffer out = new StringBuffer(context.substring(0, workDirIndex)); 
  out.append(getContextWorkDir()); 
  out.append(context.substring(endIndex+1, context.length())); 
   
  return out.toString();   
 
 
 // Add </Context> instead of  />, and \n if needed 
 private String formatContextEndTag(String context) { 
  int endContextStartTagIndex = context.indexOf(">"); 
  StringBuffer newContext = new StringBuffer();   
  if(context.charAt(endContextStartTagIndex-1) == '/') { 
   newContext.append(context.substring(0, endContextStartTagIndex-1)); 
   newContext.append(">"); 
   newContext.append("\n"); 
   newContext.append(getContextEndTag()); 
   newContext.append("\n"); 
   context = newContext.toString(); 
   endContextStartTagIndex--;  
  else { 
   int endContextTagIndex = context.indexOf(getContextEndTag()); 
   if(context.charAt(endContextTagIndex-1) != '\n') { 
    newContext.append(context.substring(0,endContextTagIndex)); 
    newContext.append("\n"); 
    newContext.append(context.substring(endContextTagIndex));     
   else { 
    return context; 
   
  
   
  return newContext.toString(); 
 
  
 private String addLoaderToContext(String context) { 
  context = this.formatContextEndTag(context); 
  int endContextStartTagIndex = context.indexOf(">");   
  int loaderIndex = endContextStartTagIndex + 1
  StringBuffer out = new StringBuffer(context.substring(0, loaderIndex)); 
  out.append(getContextWebAppClassLoader()); 
  out.append(context.substring(loaderIndex, context.length()));     
   
  return out.toString();    
 
 
 private String updateLoaderInContext(String context) { 
  context = this.formatContextEndTag(context);   
  int endContextStartTagIndex = context.indexOf(">"); 
  int startIndex = context.indexOf("<Loader", endContextStartTagIndex); 
  if(context.charAt(startIndex-1) == '\t') startIndex--; 
  if(context.charAt(startIndex-1) == '\n') startIndex--;   
  int endIndex = context.indexOf("/>",startIndex+1)+1
  StringBuffer out = new StringBuffer(context.substring(0, startIndex)); 
  out.append(getContextWebAppClassLoader()); 
  out.append(context.substring(endIndex+1, context.length())); 
   
  return out.toString();   
 
 
 private String removeLoaderInContext(String context) { 
  int endContextStartTagIndex = context.indexOf(">"); 
  int startIndex = context.indexOf("<Loader", endContextStartTagIndex); 
  if(context.charAt(startIndex-1) == '\t') startIndex--; 
  if(context.charAt(startIndex-1) == '\n') startIndex--;    
  int endIndex = context.indexOf("/>",startIndex+1)+1
  StringBuffer out = new StringBuffer(context.substring(0, startIndex)); 
  out.append(context.substring(endIndex+1, context.length())); 
   
  return out.toString();   
 
 
 private String addLoggerToContext(String context) { 
  context = this.formatContextEndTag(context); 
  int endContextStartTagIndex = context.indexOf(">");   
  int loggerIndex = endContextStartTagIndex + 1
  StringBuffer out = new StringBuffer(context.substring(0, loggerIndex)); 
  out.append(getContextLogger()); 
  out.append(context.substring(loggerIndex, context.length()));     
   
  return out.toString();    
 
 
 private String updateLoggerInContext(String context) { 
  int endContextStartTagIndex = context.indexOf(">"); 
  int startIndex = context.indexOf("<Logger", endContextStartTagIndex); 
  if(context.charAt(startIndex-1) == '\t') startIndex--; 
  if(context.charAt(startIndex-1) == '\n') startIndex--;    
  int endIndex = context.indexOf("/>",startIndex)+1
  StringBuffer out = new StringBuffer(context.substring(0, startIndex)); 
  out.append(getContextLogger()); 
  out.append(context.substring(endIndex+1, context.length())); 
   
  return out.toString();   
 
 
 private String removeLoggerInContext(String context) { 
  int endContextStartTagIndex = context.indexOf(">"); 
  int startIndex = context.indexOf("<Logger", endContextStartTagIndex); 
  if(context.charAt(startIndex-1) == '\t') startIndex--; 
  if(context.charAt(startIndex-1) == '\n') startIndex--;    
  int endIndex = context.indexOf("/>",startIndex)+1
  StringBuffer out = new StringBuffer(context.substring(0, startIndex)); 
  out.append(context.substring(endIndex+1, context.length())); 
   
  return out.toString();  
 
 
 
 private String addExtraInfoToContext(String context) { 
  context = this.formatContextEndTag(context); 
  int endContextStartTagIndex = context.indexOf(">");   
  int extraInfoIndex = endContextStartTagIndex + 1
  StringBuffer out = new StringBuffer(context.substring(0, extraInfoIndex)); 
  out.append('\n');  
  out.append(extraBeginTag); 
  out.append('\n'); 
  out.append(getExtraInfo()); 
  out.append('\n'); 
  out.append(extraEndTag);       
  out.append(context.substring(extraInfoIndex, context.length()));     
   
  return out.toString();    
 
 
 private String updateExtraInfoInContext(String context) { 
  int endContextStartTagIndex = context.indexOf(">"); 
  int startIndex = context.indexOf(extraBeginTag, endContextStartTagIndex); 
  if(context.charAt(startIndex-1) == '\t') startIndex--; 
  if(context.charAt(startIndex-1) == '\n') startIndex--;    
  int extraEndTagStartIndex = context.indexOf(extraEndTag,startIndex); 
  StringBuffer out = new StringBuffer(context.substring(0, startIndex)); 
  out.append('\n');   
  out.append(extraBeginTag); 
  out.append('\n'); 
  out.append(getExtraInfo()); 
  out.append('\n'); 
  out.append(context.substring(extraEndTagStartIndex, context.length())); 
   
  return out.toString();   
 
 
 private String removeExtraInfoInContext(String context) { 
  int endContextStartTagIndex = context.indexOf(">"); 
  int startIndex = context.indexOf(extraBeginTag, endContextStartTagIndex); 
  if(context.charAt(startIndex-1) == '\t') startIndex--; 
  if(context.charAt(startIndex-1) == '\n') startIndex--;    
  int extraEndTagStartIndex = context.indexOf(extraEndTag,startIndex); 
  StringBuffer out = new StringBuffer(context.substring(0, startIndex)); 
  int endIndex = extraEndTagStartIndex + extraEndTag.length(); 
  out.append(context.substring(endIndex, context.length())); 
   
  return out.toString();  
 
  
 private String getContextStartTag() { 
  return ("<Context"); 
 
  
 private String getContextPath() { 
  return ("path=" + '"' + getWebPath() + '"');  
 
  
 private String getContextDocBase() { 
  String docBaseLocation = ""
  if(getRootDirFolder() == null) { 
   docBaseLocation = project.getLocation().toOSString(); 
  else { 
   docBaseLocation = this.getRootDirFolder().getLocation().toOSString(); 
  
  return ("docBase=" + '"' + docBaseLocation + '"');  
 
  
 private String getContextWorkDir() { 
  String workFolderLocation = this.getWorkFolder().getLocation().toOSString(); 
  return (TomcatLauncherPlugin.getDefault().getTomcatBootstrap().getContextWorkDir(workFolderLocation)); 
 
  
 private String getContextWebAppClassLoader() { 
  return "\n\t<Loader className=\"org.apache.catalina.loader.DevLoader\" reloadable=\"true\" debug=\"1\" useSystemClassLoaderAsParent=\"false\" />"
 
  
 private String getContextLogger() { 
  return "\n\t<Logger className=\"org.apache.catalina.logger.SystemOutLogger\" verbosity=\"4\" timestamp=\"true\"/>"
 
 
 
 private String getContextEndTag() { 
  return "</Context>"
   
 
 
 public void exportToWar() throws IOException { 
 
  File warFile = new File(this.getWarLocation()); 
   
  File directory = null
   if(getRootDirFolder() == null) { 
    directory = this.getProject().getLocation().toFile(); 
   else {     
    directory = this.getRootDirFolder().getLocation().toFile(); 
   
        
  Zipper zipper = new TomcatProjectZipper(warFile, directory, getExportSource()); 
  zipper.zip(); 
 
 
 /*
  * if WEB-INF classes contains Java files add it to source folders 
  * Otherwise Eclipse will delete all those files 
  */
 
 private boolean classesContainsJavaFiles() {   
  IFolder webinfFolder = this.getWebInfFolder();  
  IFolder classesFolder = webinfFolder.getFolder("classes"); 
  File f = classesFolder.getLocation().toFile(); 
      
     if (!f.exists()) return false;  
     if (!f.isDirectory()) return false;  
     
     return FileUtil.dirContainsFiles(f, "java"true); 
 }   
  
  
 /*
  * A new Tomcat project should be checked by default in source path preference page 
  */
 
 private void addProjectToSourcePathPref() { 
  List projects = TomcatLauncherPlugin.getDefault().getProjectsInSourcePath(); 
  ProjectListElement ple = new ProjectListElement(getProject()); 
  if(!projects.contains(ple)) { 
   projects.add(ple); 
   TomcatLauncherPlugin.getDefault().setProjectsInSourcePath(projects); 
  
 
}