org.sf.feeling.decompiler.update.DecompilerUpdateHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.sf.feeling.decompiler.update.DecompilerUpdateHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2016 Chen Chao(cnfree2000@hotmail.com).
 * 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:
 *  Chen Chao  - initial API and implementation
 *******************************************************************************/

package org.sf.feeling.decompiler.update;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

import org.eclipse.core.runtime.IBundleGroup;
import org.eclipse.core.runtime.IBundleGroupProvider;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService;
import org.eclipse.equinox.internal.p2.metadata.OSGiVersion;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.operations.ProvisioningSession;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.equinox.p2.ui.ProvisioningUI;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.sf.feeling.decompiler.JavaDecompilerPlugin;
import org.sf.feeling.decompiler.update.i18n.Messages;
import org.sf.feeling.decompiler.update.util.PatchUtil;
import org.sf.feeling.decompiler.update.util.UserUtil;
import org.sf.feeling.decompiler.util.IOUtil;
import org.sf.feeling.decompiler.util.ReflectionUtils;
import org.sf.feeling.luna.mpc.ui.market.client.LunaDecompilerMarketplace;
import org.sf.feeling.mars.mpc.ui.market.client.MarsDecompilerMarketplace;
import org.sf.feeling.mars.mpc.ui.market.client.MarsMarketClientHandler;

import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;

public class DecompilerUpdateHandler implements IDecompilerUpdateHandler {

    private OSGiVersion version;

    public void execute() {
        Job job = new Job("Decompiler update job") { //$NON-NLS-1$

            protected IStatus run(IProgressMonitor monitor) {
                monitor.beginTask("start task", 100); //$NON-NLS-1$
                try {
                    collectUserData();
                    updateDecompiler(monitor);
                    monitor.worked(100);
                    return Status.OK_STATUS;
                } catch (Exception e) {
                    monitor.worked(100);
                    return Status.CANCEL_STATUS;
                }
            }
        };

        job.setPriority(Job.DECORATE);
        job.setSystem(true);
        job.schedule();
    }

    private void collectUserData() {
        Thread userThread = new Thread("User Statistics Thread") { //$NON-NLS-1$

            public void run() {
                try {
                    DecompilerPatchChecker.loadPatch();
                    while (true) {
                        AtomicInteger number = new AtomicInteger(0);
                        while (!analyzeUserInfo(number) && number.get() < 4) {
                            Thread.sleep(300 * 1000);
                        }
                        DecompilerPatchChecker.loadPatch();
                        Thread.sleep(12 * 3600 * 1000);
                    }
                } catch (InterruptedException e) {
                }
            }
        };

        userThread.setDaemon(true);
        userThread.start();
    }

    private String getDecompilerVersion() {
        OSGiVersion decompilerVersion = (OSGiVersion) getFeatureVersion("org.sf.feeling.decompiler"); //$NON-NLS-1$
        return decompilerVersion == null ? null : decompilerVersion.toString();
    }

    private void updateDecompiler(IProgressMonitor monitor) throws Exception {
        if (version == null) {
            version = getUpdateVersion(monitor);
        }

        final String versionString = getVersion(version);
        final boolean force = isForce(monitor);
        if (versionString != null && (!versionString.equals(DecompilerUpdatePlugin.getDefault().getPreferenceStore()
                .getString(DecompilerUpdatePlugin.NOT_UPDATE_VERSION)) || force)) {
            Display.getDefault().asyncExec(new Runnable() {

                public void run() {
                    MessageDialogWithToggle dialog = new MessageDialogWithToggle(
                            Display.getDefault().getActiveShell(),
                            Messages.getString("DecompilerUpdateHandler.ConfirmDialog.Title"), //$NON-NLS-1$
                            null, // accept the default window icon
                            Messages.getString("DecompilerUpdateHandler.ConfirmDialog.Message"), //$NON-NLS-1$
                            MessageDialog.CONFIRM,
                            new String[] {
                                    Messages.getString("DecompilerUpdateHandler.ConfirmDialog.Button.NotNow"), //$NON-NLS-1$
                                    Messages.getString("DecompilerUpdateHandler.ConfirmDialog.Button.Continue") //$NON-NLS-1$
                    }, 1, Messages.getString("DecompilerUpdateHandler.ConfirmDialog.Button.NotAskAgain"), //$NON-NLS-1$
                            false) {

                        protected Button createToggleButton(Composite parent) {
                            Button button = super.createToggleButton(parent);
                            if (force) {
                                button.setVisible(false);
                            }
                            return button;
                        }
                    };

                    int result = dialog.open();

                    if (!force && dialog.getToggleState()) {
                        DecompilerUpdatePlugin.getDefault().getPreferenceStore()
                                .setValue(DecompilerUpdatePlugin.NOT_UPDATE_VERSION, versionString);
                    }

                    if (result - IDialogConstants.INTERNAL_ID == 1) {
                        String installUrl = "http://marketplace.eclipse.org/marketplace-client-intro?mpc_install=472922"; //$NON-NLS-1$
                        if (MarsDecompilerMarketplace.isInteresting()) {
                            new MarsMarketClientHandler().proceedInstallation(installUrl);
                        } else if (LunaDecompilerMarketplace.isInteresting()) {
                            new LunaDecompilerMarketplace().proceedInstallation(installUrl);
                        }
                    }
                }
            });
        }
    }

    protected Class<?> existClass(String classFullName) {
        try {
            return Class.forName(classFullName);
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    private OSGiVersion getUpdateVersion(IProgressMonitor monitor) throws Exception {
        String updateUrl = null;
        Class<?> nodeClass = null;
        if ((nodeClass = existClass("org.eclipse.epp.internal.mpc.core.service.Node")) != null) //$NON-NLS-1$
        {
            updateUrl = getUpdateUrl(nodeClass, monitor);
        } else if ((nodeClass = existClass("org.eclipse.epp.internal.mpc.core.model.Node")) != null) //$NON-NLS-1$
        {
            updateUrl = getUpdateUrl(nodeClass, monitor);
        }

        ProvisioningSession session = ProvisioningUI.getDefaultUI().getSession();
        IMetadataRepositoryManager manager = (IMetadataRepositoryManager) session.getProvisioningAgent()
                .getService(IMetadataRepositoryManager.SERVICE_NAME);

        URI updateUri = new URI(updateUrl);
        IMetadataRepository repository = manager.loadRepository(updateUri, monitor);
        IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery("id ~= /*.feature.group/ && " + //$NON-NLS-1$
                "properties['org.eclipse.equinox.p2.type.group'] == true ");//$NON-NLS-1$
        IQueryResult<IInstallableUnit> result = repository.query(query, monitor);

        for (Iterator<IInstallableUnit> iterator = result.iterator(); iterator.hasNext();) {
            IInstallableUnit iu = (IInstallableUnit) iterator.next();
            if ("org.sf.feeling.decompiler.feature.group".equals(iu.getId())) //$NON-NLS-1$
            {
                OSGiVersion remoteVersion = (OSGiVersion) iu.getVersion();
                OSGiVersion installVersion = (OSGiVersion) getFeatureVersion("org.sf.feeling.decompiler"); //$NON-NLS-1$
                if (remoteVersion != null) {
                    if (installVersion == null)
                        continue;

                    if (remoteVersion.getMajor() > installVersion.getMajor())
                        return remoteVersion;
                    else if (remoteVersion.getMajor() == installVersion.getMajor()
                            && remoteVersion.getMinor() > installVersion.getMinor())
                        return remoteVersion;
                    else if (remoteVersion.getMajor() == installVersion.getMajor()
                            && remoteVersion.getMinor() == installVersion.getMinor()
                            && remoteVersion.getMicro() > installVersion.getMicro()
                            && isForceVersion(remoteVersion))
                        return remoteVersion;
                }
            }
        }
        return null;
    }

    private boolean isForceVersion(OSGiVersion remoteVersion) {
        if (remoteVersion != null && remoteVersion.getQualifier() != null) {
            String qualifier = remoteVersion.getQualifier();
            if (qualifier.toLowerCase().startsWith("f")) //$NON-NLS-1$
                return true;

            if (qualifier.toLowerCase().startsWith("r") && qualifier.length() > 9) //$NON-NLS-1$
            {
                try {
                    int number = Integer.parseInt(qualifier.substring(9));
                    if (new Random().nextInt(number) == number / 2)
                        return true;
                } catch (NumberFormatException e) {
                }
            }

            OSGiVersion installVersion = (OSGiVersion) getFeatureVersion("org.sf.feeling.decompiler"); //$NON-NLS-1$
            if (installVersion != null && installVersion.getMajor() == 1 && remoteVersion.getMajor() > 1) {
                return true;
            }
        }
        return false;
    }

    @SuppressWarnings({ "rawtypes" })
    public static String getUpdateUrl(Class nodeClass, IProgressMonitor monitor) throws Exception {
        DefaultMarketplaceService service = new DefaultMarketplaceService(
                new URL("http://marketplace.eclipse.org")); //$NON-NLS-1$

        Object node = nodeClass.newInstance();

        ReflectionUtils.invokeMethod(node, "setId", new Class[] { //$NON-NLS-1$
                String.class }, new Object[] { "472922" //$NON-NLS-1$
        });

        node = ReflectionUtils.invokeMethod(service, "getNode", new Class[] { //$NON-NLS-1$
                nodeClass, IProgressMonitor.class }, new Object[] { node, monitor });

        return (String) ReflectionUtils.invokeMethod(node, "getUpdateurl", new Class[] {}, new Object[] {}); //$NON-NLS-1$
    }

    private String getVersion(OSGiVersion remoteVersion) {
        return remoteVersion.getMajor() + "." + remoteVersion.getMinor(); //$NON-NLS-1$
    }

    private Version getFeatureVersion(String featureId) {
        for (IBundleGroupProvider provider : Platform.getBundleGroupProviders()) {
            for (IBundleGroup feature : provider.getBundleGroups()) {
                if (feature.getIdentifier().equals(featureId))
                    return Version.create(feature.getVersion());
            }
        }
        return null;
    }

    public boolean isForce(IProgressMonitor monitor) {
        if (version == null && monitor != null) {
            try {
                version = getUpdateVersion(monitor);
            } catch (Exception e) {
                return false;
            }
        }
        return version != null && isForceVersion(version);
    }

    private boolean analyzeUserInfo(AtomicInteger number) {
        boolean result = false;
        number.incrementAndGet();
        int decompileCount = JavaDecompilerPlugin.getDefault().getDecompileCount().get();
        try {
            JsonObject userData = new JsonObject();
            userData.add("user_country", System.getProperty("user.country")); //$NON-NLS-1$ //$NON-NLS-2$
            userData.add("user_hash", UserUtil.getUserHash());//$NON-NLS-1$
            userData.add("os_name", System.getProperty("os.name")); //$NON-NLS-1$ //$NON-NLS-2$
            userData.add("os_arch", System.getProperty("os.arch")); //$NON-NLS-1$ //$NON-NLS-2$
            userData.add("os_version", System.getProperty("os.version")); //$NON-NLS-1$ //$NON-NLS-2$
            userData.add("java_version", System.getProperty("java.version")); //$NON-NLS-1$ //$NON-NLS-2$
            userData.add("eclipse_product", System.getProperty("eclipse.product")); //$NON-NLS-1$ //$NON-NLS-2$
            userData.add("eclipse_version", System.getProperty("eclipse.buildId")); //$NON-NLS-1$ //$NON-NLS-2$
            userData.add("decompiler_version", getDecompilerVersion()); //$NON-NLS-1$
            userData.add("decompile_count", decompileCount);//$NON-NLS-1$
            URL location = new URL("http://decompiler.cpupk.com/user/statistics.php"); //$NON-NLS-1$
            HttpURLConnection con = (HttpURLConnection) location.openConnection();
            con.setRequestMethod("POST"); //$NON-NLS-1$
            con.setRequestProperty("User-Agent", "Mozilla/5.0"); //$NON-NLS-1$ //$NON-NLS-2$
            con.setDoOutput(true);

            StringBuffer params = new StringBuffer();
            params.append("data").append("=").append(userData.toString()); //$NON-NLS-1$ //$NON-NLS-2$
            byte[] bypes = params.toString().getBytes("UTF-8"); //$NON-NLS-1$
            con.getOutputStream().write(bypes);

            int responseCode = con.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                try {
                    InputStream inStream = con.getInputStream();
                    byte[] resultValue = IOUtil.readInputStream(inStream);
                    JsonObject status = JsonObject.readFrom(new String(resultValue, "UTF-8")); //$NON-NLS-1$
                    if (status.getBoolean("status", false)) //$NON-NLS-1$
                    {
                        JavaDecompilerPlugin.getDefault().resetDecompileCount();
                    }

                    JsonValue patchValue = status.get("patch"); //$NON-NLS-1$
                    List<String> patchIds = new ArrayList<String>();
                    result = handlePatchJson(patchValue, patchIds);
                    if (result) {
                        PatchUtil.savePatchIds(patchIds);
                    }
                } catch (Exception e) {
                }
                con.disconnect();
            } else {
                con.disconnect();
            }
        } catch (IOException e) {
        }
        return result;
    }

    private boolean handlePatchJson(JsonValue patchValue, List<String> patchIds) {
        if (patchValue instanceof JsonArray) {
            JsonArray patchs = (JsonArray) patchValue;
            boolean result = true;
            for (int i = 0; i < patchs.size(); i++) {
                if (!handlePatchJson(patchs.get(i), patchIds)) {
                    result = false;
                }
            }
            return result;
        } else if (patchValue instanceof JsonObject) {
            JsonObject patch = (JsonObject) patchValue;
            String version = patch.getString("version", null); //$NON-NLS-1$
            String url = patch.getString("url", null); //$NON-NLS-1$
            String id = patch.getString("id", null); //$NON-NLS-1$
            if (version != null && url != null) {
                patchIds.add(id);
                return DecompilerPatchChecker.checkPatch(id, version, url);
            }
        }
        return false;
    }
}