com.salesforce.ide.core.internal.utils.Utils.java Source code

Java tutorial

Introduction

Here is the source code for com.salesforce.ide.core.internal.utils.Utils.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Salesforce.com, inc..
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Salesforce.com, inc. - initial API and implementation
 ******************************************************************************/
package com.salesforce.ide.core.internal.utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.log4j.Logger;
import org.apache.xerces.parsers.DOMParser;
import org.eclipse.core.internal.resources.OS;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourceAttributes;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.osgi.framework.Bundle;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import com.salesforce.ide.api.metadata.types.MetadataExt;
import com.salesforce.ide.core.ForceIdeCorePlugin;
import com.salesforce.ide.core.internal.utils.TestContext.TestContextEnum;
import com.salesforce.ide.core.model.Component;
import com.salesforce.ide.core.services.PackageDeployService;
import com.salesforce.ide.core.services.PackageRetrieveService;
import com.sforce.soap.metadata.FileProperties;
import com.sforce.soap.metadata.ManageableState;
import com.sforce.soap.partner.fault.wsc.ApiFault;

/**
 * Common utilities methods
 */
@SuppressWarnings("restriction")
public class Utils {
    private static final Logger logger = Logger.getLogger(Utils.class);

    public static final String DIALOG_TITLE_ERROR = "Error";
    public static final String DIALOG_TITLE_WARNING = "Warning";
    public static final String TEST_CONTEXT_PROP = "TestContext";

    public static boolean isEmpty(Object obj) {
        return obj == null;
    }

    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }

    public static boolean isEmpty(Object[] objs) {
        return objs == null || objs.length == 0;
    }

    public static boolean isNotEmpty(Object[] objs) {
        return !isEmpty(objs);
    }

    public static boolean isEmpty(byte[] objs) {
        return objs == null || objs.length == 0;
    }

    public static boolean isNotEmpty(byte[] objs) {
        return !isEmpty(objs);
    }

    public static boolean isEmpty(Collection<?> col) {
        return col == null || col.isEmpty();
    }

    public static boolean isNotEmpty(Collection<?> col) {
        return !isEmpty(col);
    }

    public static boolean isEmpty(List<?> col) {
        return col == null || col.isEmpty();
    }

    public static boolean isNotEmpty(List<?> col) {
        return !isEmpty(col);
    }

    public static boolean isEmpty(Map<?, ?> map) {
        return map == null || map.isEmpty();
    }

    public static boolean isNotEmpty(Map<?, ?> map) {
        return map != null && !map.isEmpty();
    }

    public static boolean isWorkspaceCaseSensitive() {
        return Platform.OS_MACOSX.equals(Platform.getOS()) ? false
                : new java.io.File("a").compareTo(new java.io.File("A")) != 0;
    }

    public static void openForcePerspective() {
        IWorkbench workbench = ForceIdeCorePlugin.getDefault().getWorkbench();
        IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
        IWorkbenchPage page = window.getActivePage();
        IAdaptable input;

        if (page != null) {
            input = page.getInput();
        } else {
            input = ResourcesPlugin.getWorkspace().getRoot();
        }

        try {
            workbench.showPerspective(Constants.FORCE_PLUGIN_PREFIX + ".perspective", window, input);
        } catch (WorkbenchException e) {
            logger.error("Unable to open Force.com Perspective", e);
        }
    }

    public static Shell getShell() {
        Shell shell = PlatformUI.getWorkbench().getWorkbenchWindows()[0].getShell();
        return shell;
    }

    public static void openError(Exception e, String message, String details) {
        IStatus status = new Status(IStatus.ERROR, ForceIdeCorePlugin.getPluginId(), Constants.ERROR_CODE__44,
                details, e);
        ErrorDialog.openError(getShell(), DIALOG_TITLE_ERROR, message, status);
    }

    public static void openError(Throwable pThrowable, boolean includeStackTrace, String messageSummary) {
        IStatus status = null;
        messageSummary = Utils.isEmpty(messageSummary) ? ForceExceptionUtils.getRootExceptionMessage(pThrowable)
                : messageSummary;
        if (includeStackTrace && logger.isDebugEnabled()) {
            status = new MultiStatus(ForceIdeCorePlugin.getPluginId(), Constants.ERROR_CODE__44,
                    getStatusMessage(pThrowable), ForceExceptionUtils.getRootCause(pThrowable));
            addTraceToStatus((MultiStatus) status, pThrowable.getStackTrace(), IStatus.ERROR);
        } else {
            status = new Status(IStatus.ERROR, ForceIdeCorePlugin.getPluginId(), Constants.ERROR_CODE__44,
                    getStatusMessage(pThrowable), null);
        }
        openErrorDialog(DIALOG_TITLE_ERROR, messageSummary, status);
    }

    public static void openError(Shell shell, Throwable pThrowable, boolean includeStackTrace,
            String messageSummary) {
        IStatus status = null;
        messageSummary = Utils.isEmpty(messageSummary) ? ForceExceptionUtils.getRootCause(pThrowable).getMessage()
                : messageSummary;
        if (includeStackTrace && logger.isDebugEnabled()) {
            status = new MultiStatus(ForceIdeCorePlugin.getPluginId(), Constants.ERROR_CODE__44,
                    getStatusMessage(pThrowable), ForceExceptionUtils.getRootCause(pThrowable));
            addTraceToStatus((MultiStatus) status, pThrowable.getStackTrace(), IStatus.ERROR);
        } else {
            status = new Status(IStatus.ERROR, ForceIdeCorePlugin.getPluginId(), Constants.ERROR_CODE__44,
                    getStatusMessage(pThrowable), null);
        }
        openErrorDialog(shell, DIALOG_TITLE_ERROR, messageSummary, status);
    }

    public static void openWarning(Throwable pThrowable, boolean includeStackTrace, String messageSummary) {
        IStatus status = null;
        if (includeStackTrace && logger.isDebugEnabled()) {
            status = new MultiStatus(ForceIdeCorePlugin.getPluginId(), Constants.ERROR_CODE__44,
                    getStatusMessage(pThrowable), ForceExceptionUtils.getRootCause(pThrowable));
            addTraceToStatus((MultiStatus) status, pThrowable.getStackTrace(), IStatus.WARNING);
        } else {
            status = new Status(IStatus.WARNING, ForceIdeCorePlugin.getPluginId(), Constants.ERROR_CODE__44,
                    getStatusMessage(pThrowable), null);
        }
        openErrorDialog(DIALOG_TITLE_WARNING, messageSummary, status);
    }

    private static String getStatusMessage(Throwable th) {
        if (th == null) {
            return null;
        }

        if (th instanceof ApiFault) {
            ApiFault apiFault = (ApiFault) th;
            return apiFault.getExceptionCode().name() + " - " + apiFault.getExceptionMessage();
        } else if (th.getCause() instanceof ApiFault) {
            ApiFault apiFault = (ApiFault) th.getCause();
            return apiFault.getExceptionCode().name() + " - " + apiFault.getExceptionMessage();
        } else {
            return ForceExceptionUtils.getStrippedRootCauseMessage(th);
        }
    }

    private static void openErrorDialog(String type, String message, IStatus status) {
        Shell newShell = getShell();
        if (newShell == null) {
            newShell = new Shell();
        }
        ErrorDialog.openError(newShell, type, message, status);
    }

    private static void openErrorDialog(Shell shell, String type, String message, IStatus status) {
        ErrorDialog.openError(shell, type, message, status);
    }

    public static void addTraceToStatus(MultiStatus multiStatus, StackTraceElement[] trace, int errorCode) {
        for (int i = 1; i < trace.length; i++) {
            IStatus stat = new Status(errorCode, ForceIdeCorePlugin.getPluginId(), Constants.ERROR_CODE__44,
                    trace[i].getClassName() + "." + trace[i].getMethodName() + " (" + trace[i].getFileName() + " "
                            + trace[i].getLineNumber() + ")",
                    null);
            multiStatus.add(stat);
        }
    }

    public static String generateCoreExceptionLog(CoreException ex) {
        if (ex == null) {
            throw new IllegalArgumentException();
        }

        StringBuffer strBuff = new StringBuffer(ex.getMessage());
        if (ex.getStatus() != null && ex.getStatus().isMultiStatus()
                && isNotEmpty(((MultiStatus) ex.getStatus()).getChildren())) {
            strBuff.append(" Cause(s):\n");
            IStatus[] stats = ((MultiStatus) ex.getStatus()).getChildren();
            int cnt = 0;
            for (IStatus status : stats) {
                strBuff.append(" (").append(++cnt).append(") ").append(status.getMessage());
                if (status.getException() != null) {
                    strBuff.append("\n    Root Exception: ").append(status.getException().getMessage());
                }
            }

        } else if (ex.getStatus() != null) {
            strBuff.append(" Cause:\n");
            strBuff.append(" (1) ").append(ex.getStatus().getMessage());
            if (ex.getStatus().getException() != null) {
                strBuff.append("\n    Root Exception: ").append(ex.getStatus().getException().getMessage());
            }

        }
        return strBuff.toString();
    }

    public static boolean openConfirm(String pTitle, String pMessage) {
        return MessageDialog.openConfirm(getShell(), pTitle, pMessage);
    }

    public static boolean openConfirm(Shell shell, String pTitle, String pMessage) {
        return MessageDialog.openConfirm(shell, pTitle, pMessage);
    }

    public static boolean openQuestion(String pTitle, String pMessage) {
        return MessageDialog.openQuestion(getShell(), pTitle, pMessage);
    }

    public static boolean openQuestion(Shell shell, String pTitle, String pMessage) {
        return MessageDialog.openQuestion(shell, pTitle, pMessage);
    }

    public static void openError(String pTitle, String pMessage) {
        MessageDialog.openError(getShell(), pTitle, pMessage);
    }

    public static void openInfo(String pTitle, String pMessage) {
        MessageDialog.openInformation(getShell(), pTitle, pMessage);
    }

    public static void openWarn(String pTitle, String pMessage) {
        MessageDialog.openWarning(getShell(), pTitle, pMessage);
    }

    public static void openWarn(Shell shell, String pTitle, String pMessage) {
        MessageDialog.openWarning(shell, pTitle, pMessage);
    }

    public static void openDialog(IProject project, WizardDialog dialog) {
        TestContext testContext = TestContext.getTestContextBy(getTestContextEnum(project));
        testContext.execAsyncRunnables();
        dialog.open();
    }

    public static boolean openQuestion(IProject project, Shell shell, String title, String message) {
        TestContext testContext = TestContext.getTestContextBy(getTestContextEnum(project));
        testContext.execAsyncRunnables();
        return openQuestion(shell, title, message);
    }

    public static IResource getCurrentSelectionResource() {
        IWorkbenchWindow workbenchWindow = ForceIdeCorePlugin.getDefault().getWorkbench()
                .getActiveWorkbenchWindow();
        if (workbenchWindow == null) {
            return null;
        }

        ISelection selection = workbenchWindow.getSelectionService().getSelection();
        if (selection instanceof IStructuredSelection) {
            Object firstSelected = ((IStructuredSelection) selection).getFirstElement();
            if (firstSelected instanceof IResource) {
                return (IResource) firstSelected;
            }
        }
        return null;
    }

    public static IStatus getStatus(Exception e) {
        String msg = e.getMessage();
        if (e instanceof CoreException) {
            CoreException ce = (CoreException) e;
            IStatus status = ce.getStatus();
            return status;
        }
        IStatus status = new Status(IStatus.ERROR, ForceIdeCorePlugin.getPluginId(), IStatus.OK, msg, null);
        return status;
    }

    public static String getDisplayDate(Calendar cal) {
        if (cal == null) {
            return "n/a";
        }
        SimpleDateFormat formatter = new SimpleDateFormat("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
        return formatter.format(cal.getTime());
    }

    public static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
        }
    }

    public static boolean isValidFullUrl(String endpoint) {
        if (Utils.isEmpty(endpoint)) {
            return false;
        }

        try {
            new URL(endpoint);
        } catch (MalformedURLException e) {
            return false;
        }

        return true;
    }

    public static boolean validateDomainName(String domainName) {
        String oneAlpha = "(.)*((\\p{Alpha})|[-])(.)*";
        String domainIdentifier = "((\\p{Alnum})([-]|(\\p{Alnum}))*(\\p{Alnum}))|(\\p{Alnum})";
        String domainNameRule = "(" + domainIdentifier + ")((\\.)(" + domainIdentifier + "))*";
        if (domainName == null || domainName.length() > 63) {
            return false;
        }
        return domainName.matches(domainNameRule) && domainName.matches(oneAlpha);
    }

    public static String getServerNameFromUrl(String url) {
        if (Utils.isEmpty(url)) {
            return url;
        }

        String protocol = (url.startsWith(Constants.HTTPS) ? Constants.HTTPS : Constants.HTTP) + "://";
        return url.substring(url.indexOf(protocol) + protocol.length(), url.indexOf("/", protocol.length() + 1));
    }

    public static boolean isInternalMode() {
        String mode = System.getProperty(Constants.SYS_SETTING_SFDC_INTERNAL);
        return Utils.isNotEmpty(mode) && Constants.SYS_SETTING_SFDC_INTERNAL_VALUE.equals(mode) ? true : false;
    }

    public static String getDefaultSystemApiVersion() {
        String apiVersion = System.getProperty(Constants.SYS_SETTING_DEFAULT_API_VERSION);
        return Utils.isNotEmpty(apiVersion) ? apiVersion : Constants.EMPTY_STRING;
    }

    public static String getPollLimit() {
        String pollLimit = System.getProperty(Constants.SYS_SETTING_POLL_LIMIT_MILLIS);
        return Utils.isNotEmpty(pollLimit) ? pollLimit : Constants.EMPTY_STRING;
    }

    public static String getLocaleFormattedDateTime(long datetime) {
        return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.getDefault())
                .format(new Date(datetime));
    }

    public static String getCurrentFormattedDateTime() {
        return (new SimpleDateFormat(Constants.STANDARD_DATE_FORMAT)).format(new Date());
    }

    public static String getFormattedTimestamp(File file) {
        return file != null && file.exists() ? getLocaleFormattedDateTime(file.lastModified()) : null;
    }

    public static File getCacheFile(IProject project) {
        try {
            Bundle bundle = ForceIdeCorePlugin.getDefault().getBundle();
            IPath state = null;
            if (project != null) {
                state = project.getWorkingLocation(ForceIdeCorePlugin.getPluginId());
            } else {
                state = Platform.getStateLocation(bundle);
            }

            return new File(state.toFile(), Constants.CACHE_FILENAME);
        } catch (Exception e) {
            logger.warn("Unable to get cache file: " + e.getMessage());
        }
        return null;
    }

    public static URL getCacheUrl(IProject project) {
        File file = Utils.getCacheFile(project);
        if (file != null) {
            try {
                if (logger.isDebugEnabled()) {
                    logger.debug("Manifest cache file (does" + (file.exists() ? " " : " not ") + "exist): "
                            + file.toURL().toExternalForm());
                }

                return file.toURL();
            } catch (MalformedURLException e) {
                logger.warn("Unable to get url from file: " + e.getMessage());
            }
        }

        if (logger.isInfoEnabled()) {
            logger.info("Manifest cache file: n/a");
        }

        return null;
    }

    public static boolean isDebugMode() {
        String debug = System.getProperty(Constants.SYS_SETTING_DEBUG);
        return logger != null && logger.isDebugEnabled()
                || Utils.isNotEmpty(debug) && Constants.SYS_SETTING_DEBUG_VALUE.equals(debug);
    }

    public static boolean isManifestListenerEnabled() {
        String listener = System.getProperty(Constants.SYS_SETTING_MANIFEST_LISTENER);
        return Utils.isNotEmpty(listener) ? Boolean.parseBoolean(listener) : true;
    }

    public static boolean hasDefaultProperties() {
        String propFilePath = System.getProperty(Constants.SYS_SETTING_PROPERTIES);
        return Utils.isNotEmpty(propFilePath) && (new java.io.File(propFilePath)).exists();
    }

    public static Properties getDefaultProperties() {
        Properties props = null;
        String propFilePath = System.getProperty(Constants.SYS_SETTING_PROPERTIES);
        if (Utils.isEmpty(propFilePath)) {
            return props;
        }

        java.io.File propFile = new java.io.File(propFilePath);
        if (!propFile.exists()) {
            return props;
        }

        FileInputStream fis = null;
        try {
            fis = new FileInputStream(propFile);
            if (fis.available() > 0) {
                logger.debug("Loading properties found in prop file '" + propFilePath + "'");
                props = new Properties();
                props.load(fis);
            } else {
                logger.debug("No content found in prop file '" + propFilePath + "'");
            }

        } catch (Exception e) {
            logger.warn("Unable to load prop file '" + propFilePath + "'", e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    logger.error("Unable to close stream");
                }
            }
        }

        return props;
    }

    /**
     * remove service level version number from bundle version which composed by
     * <major_version_#>.<minor_version_#>.<service_level_version_#>.qualifier
     *
     * @param bundleVersion
     * @return
     */
    public static String removeServiceLevelFromPluginVersion(String bundleVersion) {
        String[] subBundleVersion = bundleVersion.split("\\.");
        StringBuffer strBuffer = new StringBuffer();
        for (int i = 0; i < subBundleVersion.length; i++) {
            if (i == 2) {
                continue; // skip service level version
            }
            strBuffer.append(subBundleVersion[i]).append(".");
        }
        String newBundleVersion = strBuffer.toString();
        return newBundleVersion.substring(0, newBundleVersion.length() - 1);
    }

    public static void logStats() {
        OperationStats[] operationsStats = new OperationStats[2];
        OperationStats aggregatedStats = new OperationStats(OperationStats.AGGREGATED_OPERATIONS);

        int idx = 0;
        if (PackageDeployService.getOperationStats() != null) {
            PackageDeployService.getOperationStats().logStats();
            operationsStats[idx] = PackageDeployService.getOperationStats();
        }

        if (PackageRetrieveService.getOperationStats() != null) {
            PackageRetrieveService.getOperationStats().logStats();
            operationsStats[++idx] = PackageRetrieveService.getOperationStats();
        }

        if (isNotEmpty(operationsStats)) {
            aggregatedStats.aggregateStats(operationsStats);
            aggregatedStats.logStats();
        }

        ForceIdeCorePlugin.logStats();

    }

    public static String timeoutToSecs(String timeout) {
        return timeoutToSecs(Long.parseLong(timeout));
    }

    public static String timeoutToSecs(long timeout) {
        return timeout < 1 ? "0 secs" : timeout / Constants.SECONDS_TO_MILISECONDS + " secs";
    }

    // REVIEWME: should this be moved to ProjectService?
    public static TestContextEnum getTestContextEnum(IProject project) {
        if (project == null) {
            return TestContextEnum.NONE;
        }
        IEclipsePreferences node = getPreferences(project);
        return node != null ? TestContextEnum.valueOf(node.get(TEST_CONTEXT_PROP, TestContextEnum.NONE.toString()))
                : TestContextEnum.NONE;
    }

    public static IEclipsePreferences getPreferences(IProject project) {
        if (project == null) {
            return null;
        }
        ProjectScope projectScope = new ProjectScope(project);
        IEclipsePreferences node = projectScope.getNode(Constants.PLUGIN_PREFIX);
        return node;
    }

    public static Method getGetter(Class<?> clazz, String field) {
        if (clazz == null) {
            return null;
        }

        Method[] methods = clazz.getDeclaredMethods();
        if (isEmpty(methods)) {
            return null;
        }

        for (Method method : methods) {
            if (Utils.isNotEmpty(field) && method.getName().startsWith("get" + field)
                    && method.getGenericParameterTypes().length == 0) {
                return method;
            }
        }

        return null;
    }

    public static List<String> getProperties(Class<?> clazz) {
        if (clazz == null) {
            return null;
        }

        List<String> properties = new ArrayList<String>();
        Method[] methods = clazz.getDeclaredMethods();
        if (isNotEmpty(methods)) {
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
                if (method.getName().startsWith("get") && method.getGenericParameterTypes().length == 0) {
                    properties.add(method.getName().substring(3));
                }
            }
        }

        return properties;
    }

    public static Object getPropertyValue(Object obj, String propertyName) throws ClassNotFoundException,
            IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        if (obj == null || propertyName == null) {
            return null;
        }

        Object propertyValue = null;
        Method getterMethod = getGetterMethod(obj.getClass(), propertyName);
        if (getterMethod != null) {
            Object[] args = null;
            propertyValue = getterMethod.invoke(obj, args);
        }
        return propertyValue;
    }

    public static Method getGetterMethod(Class<?> clazz, String methodNameWithoutGetPrefix)
            throws ClassNotFoundException {
        Method getterMethod = null;
        Method[] methods = clazz.getDeclaredMethods();
        if (isNotEmpty(methods)) {
            for (Method method : methods) {
                if (method.getName().equals("get" + methodNameWithoutGetPrefix)
                        && method.getGenericParameterTypes().length == 0) {
                    getterMethod = method;
                    break;
                }
            }
        }
        return getterMethod;
    }

    @SuppressWarnings("unchecked")
    public static Class<? extends MetadataExt> getMetadataClassForComponentType(String componentType)
            throws ClassNotFoundException {
        if (Utils.isEmpty(componentType)) {
            return null;
        }

        return (Class<? extends MetadataExt>) Class
                .forName(Constants.COMPONENT_TYPE_API_CLASS_PACKAGE + "." + componentType);
    }

    public static void saveDocument(Document doc, Bundle bundle, String fileName)
            throws IOException, TransformerException {
        IPath state = Platform.getStateLocation(bundle);
        saveDocument(doc, state.toPortableString() + File.separator + fileName);
    }

    public static void saveDocument(Document doc, String fullPath) throws IOException, TransformerException {
        File f = new File(fullPath);
        f.createNewFile();

        TransformerFactory tfactory = TransformerFactory.newInstance();
        tfactory.setAttribute("indent-number", new Integer(2));
        Transformer xform = tfactory.newTransformer();
        xform.setOutputProperty(OutputKeys.INDENT, "yes");
        // xform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",
        // "4");
        Source src = new DOMSource(doc);

        FileOutputStream stream = new FileOutputStream(f, false);
        OutputStreamWriter writer = new OutputStreamWriter(stream, Constants.FORCE_DEFAULT_ENCODING_CHARSET);
        Result result = new StreamResult(writer);
        xform.transform(src, result);
        writer.close();
    }

    public static Document loadDocument(URL fileUrl) {
        Document doc = null;
        DOMParser parser = new DOMParser();

        if (logger.isDebugEnabled()) {
            logger.debug("Loading document from " + fileUrl.toExternalForm());
        }

        try {
            InputSource inputSource = new InputSource(fileUrl.openStream());
            parser.parse(inputSource);
            doc = parser.getDocument();
        } catch (Exception e) {
            logger.warn("Unable to load document: " + e.getMessage());
        }

        return doc;
    }

    public static void adjustResourceReadOnly(IResource resource, boolean readyOnly, boolean recursive) {
        if (resource == null || !resource.exists()) {
            return;
        }

        // no need to set read-only if resource is already set to desired
        // read-only setting
        if (resource.getResourceAttributes() != null
                && resource.getResourceAttributes().isReadOnly() != readyOnly) {
            ResourceAttributes resourceAttributes = new ResourceAttributes();
            resourceAttributes.setReadOnly(readyOnly);
            try {
                resource.setResourceAttributes(resourceAttributes);
                if (logger.isDebugEnabled()) {
                    logger.debug("Set resource '" + resource.getProjectRelativePath().toPortableString()
                            + "' read-only=" + readyOnly);
                }
            } catch (CoreException e) {
                String logMessage = Utils.generateCoreExceptionLog(e);
                logger.warn("Unable to set read-only attribute on file " + resource.getName() + ": " + logMessage);
            }
        }

        if (recursive && resource instanceof IContainer) {
            try {
                IResource[] children = ((IContainer) resource).members();
                if (Utils.isNotEmpty(children)) {
                    for (IResource childResource : children) {
                        adjustResourceReadOnly(childResource, readyOnly, recursive);
                    }
                }
            } catch (CoreException e) {
                String logMessage = Utils.generateCoreExceptionLog(e);
                logger.warn("Unable to get children for folder " + resource.getName() + ": " + logMessage);
            }
        }
    }

    // !!! ADD NEW METHODS ABOVE THE FOLLOWING STRING UTILS SECTION !!!

    // (S T A R T) M O V E T O S T R I N G U T I L S
    private final static String[] IDE_INVALID_CHARS = new String[] { ">", "<", ",", ":", ";", "/", "\\" };
    private final static String[] HOST_PORT_INVALID_CHARS = new String[] { ">", "<", ",", ";", "/", "\\", " " };

    public static boolean isEqual(String str, String str2, boolean isCaseSensitive) {
        return isNotEmpty(str) && isNotEmpty(str2) ? isCaseSensitive ? str.equals(str2) : str.equalsIgnoreCase(str2)
                : false;
    }

    public static boolean isEqual(String str, String compareStr) {
        return isNotEmpty(str) && isNotEmpty(compareStr) && str.equals(compareStr);
    }

    public static boolean isNotEqual(String str, String str2) {
        return !isEqual(str, str2, true);
    }

    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }

    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    public static boolean startsWith(String str, String suffix) {
        return isNotEmpty(str) && isNotEmpty(suffix) && str.startsWith(suffix);
    }

    public static boolean endsWith(String str, String suffix) {
        return isNotEmpty(str) && isNotEmpty(suffix) && str.endsWith(suffix);
    }

    public static boolean contains(String str, String contains) {
        return isNotEmpty(str) && isNotEmpty(contains) && str.contains(contains);
    }

    public static InputStream openContentStream(String contents) {
        return new ByteArrayInputStream(contents.getBytes());
    }

    public static String getContentString(IFile file) throws IOException, CoreException {
        String contentStr = null;
        if (file != null && file.exists()) {
            StringBuffer strBuff = new StringBuffer();
            BufferedReader reader = null;
            InputStream contents = null;
            try {
                contents = file.getContents();
                reader = new BufferedReader(new InputStreamReader(contents, Constants.UTF_8));
                String line = reader.readLine();
                if (line != null) {
                    strBuff.append(line);
                }
                while ((line = reader.readLine()) != null) {
                    strBuff.append(Constants.NEW_LINE);
                    strBuff.append(line);
                }
            } catch (IOException e) {
                logger.error("Unable to load body from file " + file.getName(), e);
                throw e;
            } catch (CoreException e) {
                throw e;
            } finally {
                try {
                    if (reader != null) {
                        reader.close();
                    }
                } catch (IOException e) {
                }

                try {
                    if (contents != null) {
                        contents.close();
                    }
                } catch (IOException e) {
                }
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Loaded body size [" + strBuff.toString().getBytes().length + "] bytes from file '"
                        + file.getName() + "'");
            }

            contentStr = strBuff.toString();
        }

        return contentStr;
    }

    public static String getStringFromStream(InputStream is, long length) throws IOException {
        return getStringFromBytes(getBytesFromStream(is, length));
    }

    public static byte[] getBytesFromStream(InputStream is, long length) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
        byte[] buffer = new byte[1024];
        int len;

        while ((len = is.read(buffer)) >= 0) {
            out.write(buffer, 0, len);
        }

        is.close();
        out.close();
        return out.toByteArray();
    }

    public static String getStringFromBytes(byte[] bytes) {
        return new String(bytes);
    }

    public static byte[] getBytesFromFile(File file) throws IOException {
        if (file == null || !file.exists()) {
            return null;
        }

        return getBytesFromStream(new FileInputStream(file), file.length());
    }

    public static byte[] getBytesFromFile(IFile file) throws IOException, CoreException {
        if (file == null || !file.exists()) {
            return null;
        }

        return getBytesFromStream(file.getContents(), 0);
    }

    public static String trim(String str) {
        return Utils.isNotEmpty(str) ? str.trim() : str;
    }

    public static String replaceSpaceWithUnderscore(String str) {
        return str.replaceAll(" ", "_");
    }

    public static String stripExtension(Object obj) {
        if (obj == null) {
            return null;
        }

        String tmpName = null;
        if (obj instanceof Component) {
            tmpName = ((Component) obj).getName();
        } else if (obj instanceof IFile) {
            tmpName = ((IFile) obj).getName();
        } else if (obj instanceof String) {
            tmpName = (String) obj;
        }

        if (isNotEmpty(tmpName) && tmpName.contains(".")) {
            tmpName = tmpName.substring(0, tmpName.indexOf("."));
        }

        // strip "-meta" typically found on folder metadata files
        if (isNotEmpty(tmpName) && tmpName.endsWith("-meta")) {
            tmpName = tmpName.substring(0, tmpName.indexOf("-meta"));
        }

        return tmpName;
    }

    public static String stripSourceFolder(String filePath) {
        if (isEmpty(filePath)) {
            return filePath;
        }
        String[] folderPrefixes = new String[] { Constants.SOURCE_FOLDER_NAME + "/",
                Constants.REFERENCED_PACKAGE_FOLDER_NAME + "/" };

        for (String folderPrefix : folderPrefixes) {
            if (filePath.startsWith(folderPrefix)) {
                return filePath.substring(filePath.indexOf(folderPrefix) + folderPrefix.length());
            }
        }

        return filePath;
    }

    public static String stripNamespace(String str, String namespace) {
        if (isEmpty(namespace) || isEmpty(str) || !str.startsWith(namespace + Constants.NAMESPACE_SEPARATOR)) {

            return str;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Remove prepended namespace '" + namespace + "' from '" + str + "'");
        }

        return str.substring(namespace.length() + Constants.NAMESPACE_SEPARATOR.length());
    }

    public static String getNameFromFilePath(String filePath) {
        if (isNotEmpty(filePath) && filePath.contains("/")) {
            int idx = filePath.lastIndexOf("/") + 1;
            filePath = filePath.substring(idx);
            if (isNotEmpty(filePath) && filePath.contains(".")) {
                filePath = stripExtension(filePath);
            }
        }
        return filePath;
    }

    public static String getPlural(String str) {
        if (isEmpty(str)) {
            return str;
        }

        if (str.endsWith("x") || str.endsWith("ss")) {
            return str + "es";
        } else if (str.endsWith("s")) {
            return str;
        } else {
            return str + "s";
        }
    }

    public static String stripUnsupportedChars(String str) {
        if (isEmpty(str)) {
            return str;
        }
        return str.replaceAll(":", "");
    }

    public static boolean isAlphaNumericValid(String str) {
        if (isEmpty(str)) {
            return true;
        }
        String regex = "(\\w+)";
        return str.matches(regex);
    }

    /**
     * Metadata names are (where needed) encoded such that they are reasonable
     * file names & do not contain '.'. The basic encoding is URL encoding,
     * excluding '+' (spaces are preserved), but also escaping '.' to '%2E' and
     * '__' to '%5F%5F'
     */
    public static String encode(String name) {
        if (isEmpty(name)) {
            return name;
        }

        try {
            String replaceStr = URLEncoder.encode(name, Constants.FORCE_DEFAULT_ENCODING_CHARSET);
            replaceStr = replaceStr.replace('+', ' ');
            // Javadoc of URLEncoder.encode() - The special characters ".", "-",
            // "*", and "_" remain the same.
            // replaceStr = replaceStr.replace(".", "%2E");
            // replaceStr = replaceStr.replace("__", "%5F%5F");

            if (logger.isDebugEnabled() && !name.equals(replaceStr)) {
                logger.debug("Encoded name '" + name + "' to '" + replaceStr + "'");
            }

            return replaceStr;
        } catch (UnsupportedEncodingException uee) {
            throw new RuntimeException(uee);
        }
    }

    public static boolean containsInvalidChars(String str) {
        if (isEmpty(str)) {
            return false;
        }

        for (String invalidChar : getInvalidChars()) {
            if (str.contains(invalidChar)) {
                return true;
            }
        }

        return false;
    }

    protected static String[] getInvalidChars() {
        Set<String> invalidCharSet = new HashSet<String>();
        // invalid resource chars provided by eclipse platform
        for (char osInvalidChar : OS.INVALID_RESOURCE_CHARACTERS) {
            invalidCharSet.add(String.valueOf(osInvalidChar));
        }
        // invalid chars defined by IDE
        for (String ideInvalidChar : IDE_INVALID_CHARS) {
            invalidCharSet.add(ideInvalidChar);
        }
        return invalidCharSet.toArray(new String[invalidCharSet.size()]);
    }

    public static boolean containsInvalidHostPortChars(String str) {
        if (isEmpty(str)) {
            return false;
        }

        for (String invalidChar : HOST_PORT_INVALID_CHARS) {
            if (str.contains(invalidChar)) {
                return true;
            }
        }

        return false;
    }

    public static String stripNonAlphaNumericChars(String str) {
        if (isEmpty(str)) {
            return str;
        }
        str = str.replaceAll("[^a-zA-Z0-9 _]", ""); // clean up nonAlphaNumeric
        // char in front/trail of _.
        // Ex. -__a__b__c__- would
        // become __a__b__c__
        str = str.replaceAll("^_*", ""); // strips all starting "_". Ex
        // __a__b__c__ would become
        // a__b__c__
        str = str.replaceAll("_*$", ""); // strips all trailing "_". Ex
        // a__b__c__ would become a__b__c
        str = str.replaceAll("_+", "_"); // replaces all leftover multiple
        // occurances of "_" with 1 "_". Ex.
        // a__b__c would become a_b_c
        return str;
    }

    public static boolean containsNonAlphaNumericChars(String str) {
        if (isEmpty(str)) {
            return false;
        }

        Pattern p = Pattern.compile("[^a-zA-Z0-9]");
        return p.matcher(str).matches();
    }

    public static String generateNameFromLabel(String str) {
        if (isEmpty(str)) {
            return str;
        }

        if (startsWithNumeric(str)) {
            str = "X" + str;
        }

        str = stripNonAlphaNumericChars(str);
        return replaceSpaceWithUnderscore(str);
    }

    public static boolean startsWithNumeric(String str) {
        if (isEmpty(str)) {
            return false;
        }

        Pattern p = Pattern.compile("[0-9].*");
        return p.matcher(str).matches();
    }

    public static String capitalizeFirstLetter(String name) {
        return isNotEmpty(name) ? Character.toUpperCase(name.charAt(0)) + name.toLowerCase().substring(1) : name;
    }

    /**
     *
     * @param name
     *            - string need to cap first letter and letter after specific
     *            token
     * @param token
     *            - token
     * @param escape
     *            - does this token needs escape?
     * @return
     */
    public static String capFirstLetterAndLetterAfterToken(String name, String token, boolean escape) {
        if (name.indexOf(token.toUpperCase()) == -1 && name.indexOf(token.toLowerCase()) == -1) {
            return capitalizeFirstLetter(name);
        }
        String[] segments = name.toLowerCase().split(escape ? "\\" + token : token.toLowerCase()); // escaping .
        StringBuffer sb = new StringBuffer();
        for (String segment : segments) {
            sb = sb.append(capitalizeFirstLetter(segment)).append(token.toLowerCase());
        }
        return sb.substring(0, sb.length() - 1);
    }

    public static boolean firstLetterCapitalized(String name) {
        return isNotEmpty(name) ? Character.isUpperCase(name.charAt(0)) : false;
    }

    public static String camelCaseToSpaces(String str) {
        if (isEmpty(str)) {
            return str;
        }

        StringBuffer result = new StringBuffer();
        char prevChar = ' ';

        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (Character.isUpperCase(c) && !Character.isUpperCase(prevChar)) {
                result.append(' ');
                result.append(Character.toUpperCase(c));
            } else {
                result.append(c);
            }

            prevChar = c;
        }

        return result.toString();
    }

    /**
     * Return null if filePath doesn't have file extension but this method will
     * fail: 1) if filePath param doesn't have valid file extension and having .
     * in filePath 2) if filePath is pointing to folder metadata file See
     * testcase: UtilsTest_unit.testGetExtensionFromFilePath() for usage
     */
    public static String getExtensionFromFilePath(String filePath) {
        if (Utils.isEmpty(filePath)) {
            logger.error("Filepath cannot be null");
            throw new IllegalArgumentException("Filepath cannot be null");
        }

        String fileExtension = null;
        String[] splitFilePath = filePath.split("\\.");
        if (splitFilePath.length == 1) {
            return null; // no extension found!
        }
        if (filePath.endsWith(Constants.DEFAULT_METADATA_FILE_EXTENSION)) {
            // if it's metadata file, file extension should be
            // <component-file-extension>-meta.xml
            fileExtension = splitFilePath[splitFilePath.length - 2] + Constants.DOT
                    + splitFilePath[splitFilePath.length - 1];
        } else {
            // if it's regular component file, file extension should very last
            // string append after .
            fileExtension = splitFilePath[splitFilePath.length - 1];
        }
        return fileExtension;

    }

    public static boolean isSkipCompatibilityCheck() {
        String mode = System.getProperty(Constants.SYS_SETTING_SKIP_COMPATIBILITY_CHECK);
        return Utils.isNotEmpty(mode) && Constants.SYS_SETTING_SKIP_COMPATIBILITY_CHECK_VALUE.equals(mode) ? true
                : false;
    }

    public static boolean isUpgradeEnabled() {
        String mode = System.getProperty(Constants.SYS_SETTING_UPGRADE_ENABLE);
        return Utils.isEmpty(mode) || isEqual("true", mode) ? true : false;
    }

    /**
     * if the input array contains any packaged components, returns a new
     * FileProperties array which lacks any packaged components otherwise just
     * returns the input array
     */

    public static FileProperties[] removePackagedFiles(FileProperties[] props, String organizationNamespace) {
        if (Utils.isEmpty(props)) {
            logger.debug("Input file properties is empty. Skip remove packaged file check.");
            return props;
        }

        List<FileProperties> newProps = new ArrayList<FileProperties>();

        for (FileProperties prop : props) {
            if (prop.getManageableState() != ManageableState.installed && (Utils.isEmpty(prop.getNamespacePrefix())
                    || prop.getNamespacePrefix().equals(organizationNamespace))) {
                newProps.add(prop);
            }

            else if (logger.isDebugEnabled()) {
                logger.debug(prop.getFullName() + " removed from FileProperties"); //$NON-NLS-1$
            }
        }

        if (newProps.size() != props.length) {
            return newProps.toArray(new FileProperties[newProps.size()]);
        }

        return props;
    }

    public static String replaceColonToSurroundingGenericBlock(String type) {
        return type.indexOf(":") > -1 ? type.replace(":", "<") + ">" : type; // replace
        // List:@KeyType
        // to
        // List<@KeyType>
    }

    public static String recursiveReplaceAll(String str, String regex, String replacement) {
        String replaced = str.replaceAll(regex, replacement);
        boolean flag = true;
        while (flag) {
            String replaced_again = replaced.replaceAll(regex, replacement);
            if (replaced.equalsIgnoreCase(replaced_again)) {
                flag = false;
            } else {
                replaced = replaced_again;
            }
        }
        return replaced;
    }
}