net.sf.eclipse.tomcat.TomcatProject.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.eclipse.tomcat.TomcatProject.java

Source

/*
 * The MIT License (c) Copyright Sysdeo SA 2001-2002 (c) Copyright Eclipse Tomcat Plugin 2014-2016
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package net.sf.eclipse.tomcat;

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 net.sf.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_WORKDIR = "workDir";
    private static final String KEY_EXTRAINFO = "extraInfo";
    private static final String KEY_SMARTMAVENCLASSPATH = "mavenClasspath";
    private static final String extraBeginTag = "<!-- Extra info begin -->";
    private static final String extraEndTag = "<!-- Extra info end -->";

    /**
     * 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 workDir = "";
    protected String extraInfo = "";
    protected boolean updateXml;
    protected boolean exportSource;
    protected boolean reloadable = true;
    protected boolean redirectLogger = false;
    protected boolean mavenClasspath = false;
    protected WebClassPathEntries webClassPathEntries;

    protected IFolder rootDirFolder;
    protected IFolder workDirFolder;

    /**
     * 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;
    }

    public void configure() throws CoreException {
        // empty implementation
    }

    public void deconfigure() throws CoreException {
        // empty implementation
    }

    public IJavaProject getJavaProject() {
        return javaProject;
    }

    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 rootDir.
     *
     * @return Returns a String
     */
    public String getWorkDir() {
        return this.readProperty(KEY_WORKDIR);
    }

    /**
     * Sets the rootDir.
     *
     * @param rootDir The rootDir to set
     */
    public void setWorkDir(String wd) {
        this.workDir = wd;
        this.workDirFolder = 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 Boolean.parseBoolean(this.readProperty(KEY_UPDATEXML));
    }

    /**
     * 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 Boolean.parseBoolean(reloadableProperty);
    }

    /**
     * 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 Boolean.parseBoolean(redirectLoggerProperty);
    }

    /**
     * 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;
    }

    public boolean getMavenClasspath() {
        return Boolean.valueOf(this.readProperty(KEY_SMARTMAVENCLASSPATH)).booleanValue();
    }

    public void setMavenClasspath(boolean mavenClasspath) {
        this.mavenClasspath = mavenClasspath;
    }

    /**
     * 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("    <workDir>" + workDir + "</workDir>\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("    <mavenClasspath>" + mavenClasspath + "</mavenClasspath>\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 (IClasspathEntry entrie : entries) {
            if (entrie.getEntryKind() != IClasspathEntry.CPE_SOURCE) {
                cp.add(entrie);
            }
        }
        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 (IClasspathEntry entrie : entries) {
            IClasspathEntry entry = entrie;
            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 (IResource libFile : libFiles) {
            if ((libFile.getType() == IResource.FILE) && (libFile.getFileExtension().equalsIgnoreCase("jar"))) {
                cp.add(JavaCore.newLibraryEntry(libFile.getFullPath(), null, null));
            }
        }

        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() {
        return project.getFolder(getWorkDir());
    }

    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"), getWorkDir());

    }

    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(false, true, null); //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()), 0, null);
        } 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 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);
            if (endTagIndex < 0) {
                endTagIndex = xml.indexOf('>', contextTagIdx);
            } else {
                endTagIndex += "</Context>".length();
            }

            StringBuffer out = null;

            out = new StringBuffer(xml.substring(0, contextTagIdx));
            out.append(xml.substring(endTagIndex + 1, xml.length()));
            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) {
        return (getContextTagIndex(xml) != -1);
    }

    private int getContextTagIndex(String xml) {
        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 || getMavenClasspath()) {

            context = this.addLoaderToContext(context);
        }
        if (getRedirectLogger()) {
            context = this.addLoggerToContext(context);
        }
        if (!(getExtraInfo().equals(""))) {
            context = this.addExtraInfoToContext(context);
        }

        return context;

    }

    private String updateContextDefinition(String context) {
        String ctx = context;

        // if reloadable param not set
        int reloadableIndex = ctx.indexOf("reloadable");
        if (reloadableIndex == -1) {
            ctx = this.addReloadableToContext(ctx);
        } else {
            ctx = this.updateReloadableInContext(ctx);
        }

        // update docBase if set
        int docBaseIndex = ctx.indexOf("docBase");
        if (docBaseIndex == -1) {
            ctx = this.addDocBaseToContext(ctx);
        } else {
            ctx = this.updateDocBaseInContext(ctx);
        }

        // if work param not set
        int workIndex = ctx.indexOf("workDir");
        if (workIndex == -1) {
            ctx = this.addWorkToContext(ctx);
        } else {
            ctx = this.updateWorkInContext(ctx);
        }

        // if loader not set
        int loaderIndex = ctx.indexOf("<Loader");
        if ((loaderIndex == -1) && (getWebClassPathEntries() != null) || getMavenClasspath()) {
            ctx = this.addLoaderToContext(ctx);
        }
        if ((loaderIndex != -1) && (getWebClassPathEntries() == null) && !getMavenClasspath()) {
            ctx = this.removeLoaderInContext(ctx);
        }
        if ((loaderIndex != -1) && (getWebClassPathEntries() != null) || getMavenClasspath()) {
            ctx = this.updateLoaderInContext(ctx);
        }

        // if logger not set
        int loggerIndex = ctx.indexOf("<Logger");
        if ((loggerIndex == -1) && getRedirectLogger()) {
            ctx = this.addLoggerToContext(ctx);
        }
        if ((loggerIndex != -1) && !getRedirectLogger()) {
            ctx = this.removeLoggerInContext(ctx);
        }
        if ((loggerIndex != -1) && getRedirectLogger()) {
            ctx = this.updateLoggerInContext(ctx);
        }

        // Extra info
        int extraInfoIndex = ctx.indexOf(extraBeginTag);
        if ((extraInfoIndex == -1) && !(getExtraInfo().equals(""))) {
            ctx = this.addExtraInfoToContext(ctx);
        }
        if ((extraInfoIndex != -1) && getExtraInfo().equals("")) {
            ctx = this.removeExtraInfoInContext(ctx);
        }
        if ((extraInfoIndex != -1) && !(getExtraInfo().equals(""))) {
            ctx = this.updateExtraInfoInContext(ctx);
        }
        return ctx;
    }

    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) {
        String ctx = context;
        int endContextStartTagIndex = ctx.indexOf(">");
        StringBuffer newContext = new StringBuffer();
        if (ctx.charAt(endContextStartTagIndex - 1) == '/') {
            newContext.append(ctx.substring(0, endContextStartTagIndex - 1));
            newContext.append(">");
            newContext.append("\n");
            newContext.append(getContextEndTag());
            newContext.append("\n");
            ctx = newContext.toString();
            endContextStartTagIndex--;
        } else {
            int endContextTagIndex = ctx.indexOf(getContextEndTag());
            if (ctx.charAt(endContextTagIndex - 1) != '\n') {
                newContext.append(ctx.substring(0, endContextTagIndex));
                newContext.append("\n");
                newContext.append(ctx.substring(endContextTagIndex));
            } else {
                return ctx;
            }
        }

        return newContext.toString();
    }

    private String addLoaderToContext(String context) {
        String ctx = this.formatContextEndTag(context);
        int endContextStartTagIndex = ctx.indexOf(">");
        int loaderIndex = endContextStartTagIndex + 1;
        StringBuffer out = new StringBuffer(ctx.substring(0, loaderIndex));
        out.append(getContextWebAppClassLoader());
        out.append(ctx.substring(loaderIndex, ctx.length()));

        return out.toString();
    }

    private String updateLoaderInContext(String context) {
        String ctx = this.formatContextEndTag(context);
        int endContextStartTagIndex = ctx.indexOf(">");
        int startIndex = ctx.indexOf("<Loader", endContextStartTagIndex);
        if (ctx.charAt(startIndex - 1) == '\t') {
            startIndex--;
        }
        if (ctx.charAt(startIndex - 1) == '\n') {
            startIndex--;
        }
        int endIndex = ctx.indexOf("/>", startIndex + 1) + 1;
        StringBuffer out = new StringBuffer(ctx.substring(0, startIndex));
        out.append(getContextWebAppClassLoader());
        out.append(ctx.substring(endIndex + 1, ctx.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) {
        String ctx = this.formatContextEndTag(context);
        int endContextStartTagIndex = ctx.indexOf(">");
        int loggerIndex = endContextStartTagIndex + 1;
        StringBuffer out = new StringBuffer(ctx.substring(0, loggerIndex));
        out.append(getContextLogger());
        out.append(ctx.substring(loggerIndex, ctx.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) {
        String ctx = this.formatContextEndTag(context);
        int endContextStartTagIndex = ctx.indexOf(">");
        int extraInfoIndex = endContextStartTagIndex + 1;
        StringBuffer out = new StringBuffer(ctx.substring(0, extraInfoIndex));
        out.append('\n');
        out.append(extraBeginTag);
        out.append('\n');
        out.append(getExtraInfo());
        out.append('\n');
        out.append(extraEndTag);
        out.append(ctx.substring(extraInfoIndex, ctx.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);
        }
    }
}