com.nokia.tools.variant.confml.ui.wizards.ImportCPFPage3.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.tools.variant.confml.ui.wizards.ImportCPFPage3.java

Source

/*
 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 * 
 * Initial Contributors:
 * Nokia Corporation - Initial contribution
 * 
 * Contributors:
 * 
 * Description: This file is part of com.nokia.tools.variant.confml.ui component.
 */

package com.nokia.tools.variant.confml.ui.wizards;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.SecretKeySpec;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TreeColumn;
import org.w3c.dom.Document;

import com.nokia.tools.variant.confml.ui.ConfmlUI;
import com.nokia.tools.variant.confml.ui.IConfmlImages;
import com.nokia.tools.vct.common.appmodel.EConfMLLayer;
import com.nokia.tools.vct.common.appmodel.EConfigurationProject;
import com.nokia.tools.vct.common.appmodel.EStorageClass;
import com.nokia.tools.vct.common.appmodel.util.AppModelFactory;
import com.nokia.tools.vct.common.appmodel.util.CPFSigningUtils;
import com.nokia.tools.vct.common.appmodel.util.CPFUtil;
import com.nokia.tools.vct.common.appmodel.util.ICPFContentProvider;
import com.nokia.tools.vct.common.core.utils.FileUtils;
import com.nokia.tools.vct.common.secure.core.SigningStatus;
import com.nokia.tools.vct.common.secure.core.SigningUtils;

public class ImportCPFPage3 extends WizardPage {

    class ProjectContentsLabelProvider extends LabelProvider implements ITableLabelProvider {
        public Image getColumnImage(Object element, int columnIndex) {
            if (columnIndex != 0) {
                return null;
            }

            if (element instanceof EConfigurationProject) {
                return ConfmlUI.getImage(IConfmlImages.FLD_PROJECT);
            } else if (element instanceof EConfMLLayer) {
                return ConfmlUI.getImage(IConfmlImages.FLD_LAYER);
            } else {
                return null;
            }
        }

        public String getColumnText(Object element, int columnIndex) {
            if (columnIndex == 0) {
                if (element instanceof EConfigurationProject) {
                    EConfigurationProject project = (EConfigurationProject) element;
                    URI uri = project.getRootConfml();
                    if (uri.isPlatform()) {
                        IPath path = new Path(uri.toPlatformString(true)).removeFirstSegments(1);
                        ;
                        return path.toString();
                    } else {
                        return uri.path();
                    }

                } else if (element instanceof EConfMLLayer) {
                    EConfMLLayer layer = (EConfMLLayer) element;
                    URI uri = layer.getRootConfml();
                    if (uri.isPlatform()) {
                        IPath path = new Path(uri.toPlatformString(true)).removeFirstSegments(1);
                        ;
                        return path.toString();
                    } else {
                        return uri.path();
                    }
                } else {
                    return null;
                }
            } else if (columnIndex == 1) {
                URI uri;
                SigningStatus status;
                if (element instanceof EConfigurationProject) {
                    EConfigurationProject project = (EConfigurationProject) element;
                    uri = CPFSigningUtils.getSignatureURI(project);
                } else if (element instanceof EConfMLLayer) {
                    EConfMLLayer layer = (EConfMLLayer) element;
                    uri = CPFSigningUtils.getSignatureURI(layer);
                } else {
                    return null;
                }
                status = statusMap.get(uri);
                if (status == null) {
                    return "error";
                } else if (!status.signatureFound) {
                    return "unsigned";
                } else if (!status.contentOK) {
                    return "modified";
                } else {
                    return "signed";
                }
            } else if (columnIndex == 2) {
                URI uri;
                SigningStatus status;
                if (element instanceof EConfigurationProject) {
                    EConfigurationProject project = (EConfigurationProject) element;
                    uri = CPFSigningUtils.getSignatureURI(project);
                } else if (element instanceof EConfMLLayer) {
                    EConfMLLayer layer = (EConfMLLayer) element;
                    uri = CPFSigningUtils.getSignatureURI(layer);
                } else {
                    return null;
                }
                status = statusMap.get(uri);
                if (status == null) {
                    return null;
                } else if (status.certificate == null) {
                    return "n/a";
                } else {
                    return SigningUtils.getShortName(status.certificate);
                }
            } else {
                return null;
            }
        }
    }

    static final String PAGE_NAME = ImportCPFPage3.class.getName();

    private TreeViewer viewer;
    private List<EConfigurationProject> projects = new ArrayList<EConfigurationProject>();
    private Map<URI, Document> signatures = new LinkedHashMap<URI, Document>();
    private Map<URI, SigningStatus> statusMap = new LinkedHashMap<URI, SigningStatus>();
    private Map<URI, byte[]> digestMap = new LinkedHashMap<URI, byte[]>();
    private List<URI> resources = new ArrayList<URI>();

    public ImportCPFPage3() {
        super(PAGE_NAME);

        setTitle("CPF Contents Information");
    }

    public void createControl(Composite parent) {
        Composite control = new Composite(parent, SWT.NONE);
        TreeColumnLayout layout = new TreeColumnLayout();
        control.setLayout(layout);

        viewer = new TreeViewer(control, SWT.FULL_SELECTION | SWT.BORDER);
        viewer.getTree().setHeaderVisible(true);
        TreeColumn column1 = new TreeColumn(viewer.getTree(), SWT.LEFT);
        TreeColumn column2 = new TreeColumn(viewer.getTree(), SWT.LEFT);
        TreeColumn column3 = new TreeColumn(viewer.getTree(), SWT.LEFT);
        column1.setText("Element");
        column2.setText("State");
        column3.setText("Certificate");
        layout.setColumnData(column1, new ColumnWeightData(15, 200));
        layout.setColumnData(column2, new ColumnWeightData(5, 60));
        layout.setColumnData(column3, new ColumnWeightData(10, 150));

        viewer.setLabelProvider(new ProjectContentsLabelProvider());
        viewer.setContentProvider(new ExportCPFPage1.ProjectContentsContentProvider());
        viewer.setInput(projects);

        setControl(control);
    }

    @Override
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        ImportCPFPage1 page1 = (ImportCPFPage1) getWizard().getPage(ImportCPFPage1.PAGE_ID);
        final ICPFContentProvider contentProvider = page1.getContentProvider();

        if (visible) {
            Display.getCurrent().asyncExec(new Runnable() {
                public void run() {

                    resources.clear();
                    projects.clear();
                    signatures.clear();
                    digestMap.clear();
                    statusMap.clear();
                    viewer.refresh();

                    IRunnableWithProgress scan = new IRunnableWithProgress() {
                        public void run(IProgressMonitor monitor)
                                throws InvocationTargetException, InterruptedException {
                            scan(monitor, contentProvider);
                        }
                    };
                    try {
                        getContainer().run(false, false, scan);
                    } catch (Exception e) {
                        // IMPROVEMENT Auto-generated catch block
                        e.printStackTrace();
                    }
                    viewer.refresh();
                }
            });
        }
    }

    protected ZipInputStream openStream(File source, EStorageClass storageClass, Cipher cipher) throws IOException {
        InputStream is = new BufferedInputStream(new FileInputStream(source));

        switch (storageClass) {
        case PKZIP:
            return new ZipInputStream(is);
        case ENCRYPTED:
            DataInputStream dis = new DataInputStream(is);
            dis.skip(2);
            int len = dis.readInt();
            dis.skip(len - 4);
            is = new CipherInputStream(dis, cipher);
            return new ZipInputStream(is);
        default:
            throw new IOException();
        }
    }

    Cipher createCipher(String algorithm, SecretKeySpec keySpec) {
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(algorithm);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
        } catch (Exception e) {
            // IMPROVEMENT Auto-generated catch block
            e.printStackTrace();
        }
        return cipher;
    }

    void scan(IProgressMonitor monitor, ICPFContentProvider contentProvider) {

        ZipInputStream zis;
        try {

            monitor.beginTask("Scanning contents", 1500);

            List<URI> roots = new ArrayList<URI>();
            ResourceSet resourceSet = CPFUtil.createCPFResourceSet(contentProvider);

            zis = CPFUtil.openCPFStream(contentProvider);
            try {
                prepare(new SubProgressMonitor(monitor, 500), zis, resourceSet, roots);
            } finally {
                FileUtils.closeStream(zis);
            }
            zis = CPFUtil.openCPFStream(contentProvider);
            try {
                finalize(new SubProgressMonitor(monitor, 500), resourceSet, roots);
            } finally {
                FileUtils.closeStream(zis);
            }
            zis = CPFUtil.openCPFStream(contentProvider);
            try {
                validate(new SubProgressMonitor(monitor, 500), resourceSet);
            } finally {
                FileUtils.closeStream(zis);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return;
        } catch (Error e) {
            e.printStackTrace();
            return;
        } finally {
            monitor.done();
        }
    }

    class HashProvider implements SigningUtils.IDigestVerifyer {

        private URI base;

        public HashProvider(URI base) {
            this.base = base;
        }

        public boolean isDigestCorrect(URI uri, byte[] digest) {
            URI resolved = uri.resolve(base);

            byte[] calculated = digestMap.get(resolved);
            if (calculated == null) {
                // missing digest
                return false;
            }
            boolean match = Arrays.equals(calculated, digest);
            return match;
        }
    }

    private void validate(IProgressMonitor monitor, ResourceSet resourceSet) {
        monitor.beginTask("Validating signatures", 10 * projects.size());

        URI baseURI = com.nokia.tools.vct.common.appmodel.util.CPFUtil.CPF_BASE_URI;

        for (EConfigurationProject project : projects) {
            URI signatureURI = CPFSigningUtils.getSignatureURI(project);
            Document document = signatures.get(signatureURI);

            // the content is in "/xxx.confml" form
            URI content = project.getRootConfml().deresolve(baseURI);
            content = URI.createURI(content.toString().substring(1));

            SigningStatus status = SigningUtils.getSigningStatus(document,
                    new HashProvider(com.nokia.tools.vct.common.appmodel.util.CPFUtil.CPF_BASE_URI),
                    Collections.singleton(content));
            statusMap.put(signatureURI, status);

            for (EConfMLLayer layer : project.getLayers()) {
                Set<URI> copy = new HashSet<URI>();
                for (URI next : layer.getLayerFiles()) {
                    if ("sign".equals(next.fileExtension())) {
                        continue;
                    } else if (next.lastSegment().length() == 0) {
                        continue;
                    }
                    URI uri = next.deresolve(layer.getLayerURI());
                    copy.add(uri);
                }
                signatureURI = CPFSigningUtils.getSignatureURI(layer);
                document = signatures.get(signatureURI);
                status = SigningUtils.getSigningStatus(document, new HashProvider(layer.getLayerURI()), copy);
                statusMap.put(signatureURI, status);
            }

            monitor.worked(10);
        }

        monitor.done();
    }

    private void finalize(IProgressMonitor monitor, ResourceSet resourceSet, List<URI> roots) {
        monitor.beginTask("Generating models", 100 * roots.size());

        for (URI next : roots) {
            EConfigurationProject project;
            try {
                project = new AppModelFactory().populateProject(new SubProgressMonitor(monitor, 100), resourceSet,
                        next, resources);
            } catch (InterruptedException e) {
                e.printStackTrace();
                continue;
            }
            projects.add(project);
        }
        monitor.done();
    }

    private void prepare(IProgressMonitor monitor, ZipInputStream zis, ResourceSet resourceSet, List<URI> roots)
            throws IOException, Exception {
        monitor.beginTask("Preloading contents & computing digests", 100);

        int totalWork = 100;
        int currentIncrement = 4;
        int halfWay = totalWork / 2;
        int nextProgress = currentIncrement;
        int worked = 0;

        for (ZipEntry entry = zis.getNextEntry(); entry != null; entry = zis.getNextEntry()) {
            Path path = new Path(entry.getName());
            String[] segments = path.segments();
            for (int i = 0; i < segments.length; i++) {
                segments[i] = URI.encodeSegment(segments[i], false);
            }

            URI entryURI = URI.createHierarchicalURI(segments, null, null).resolve(CPFUtil.CPF_BASE_URI);
            if (entry.isDirectory()) {
                entryURI = entryURI.appendSegment("");
            }

            resources.add(entryURI);

            if (!entry.isDirectory()) {
                MessageDigest digest = MessageDigest.getInstance("SHA");
                DigestInputStream disStream = new DigestInputStream(zis, digest) {
                    byte[] buffer = new byte[1024];

                    @Override
                    public long skip(long n) throws IOException {
                        long result = 0;
                        while (n > 0) {
                            int toSkip = (int) Math.min(buffer.length, n);
                            int res = read(buffer, 0, toSkip);
                            if (res >= 0) {
                                n -= res;
                                result += res;
                            } else {
                                break;
                            }
                        }
                        return result;
                    }

                    @Override
                    public void close() throws IOException {
                    }

                };
                FilterInputStream noCloseStream = new FilterInputStream(disStream) {
                    @Override
                    public void close() throws IOException {
                    }
                };

                if ("confml".equals(entryURI.fileExtension())) {

                    Resource resource = resourceSet.createResource(entryURI);
                    resource.load(noCloseStream, null);
                    resourceSet.getResources().add(resource);

                    if (entryURI.segmentCount() == 1) {
                        // root confml
                        roots.add(entryURI);
                    }

                } else if ("sign".equals(entryURI.fileExtension())) {
                    Document doc = SigningUtils.unmarshalSignature(noCloseStream);
                    signatures.put(entryURI, doc);
                }

                noCloseStream.skip(Integer.MAX_VALUE);

                byte[] data = digest.digest();
                digestMap.put(entryURI, data);
            }

            if (--nextProgress <= 0) {
                monitor.worked(1);
                worked++;
                if (worked >= halfWay) {
                    currentIncrement *= 2;
                    halfWay += (totalWork - halfWay) / 2;
                }
                nextProgress = currentIncrement;
            }

            zis.closeEntry();
        }

        monitor.done();
    }
}