[Title] common-eplugin: added incremental sign model
authorJihoon Song <jihoon80.song@samsung.com>
Thu, 28 Feb 2013 11:27:43 +0000 (20:27 +0900)
committerJihoon Song <jihoon80.song@samsung.com>
Tue, 5 Mar 2013 10:57:59 +0000 (19:57 +0900)
[Desc.]
[Issue] #8446

Change-Id: Idb932097099674d92ad8f39ad4282650ee5d0c80

12 files changed:
org.tizen.common.sign/plugin.xml
org.tizen.common.sign/src/org/tizen/common/sign/SigningPrompter.java [new file with mode: 0644]
org.tizen.common.sign/src/org/tizen/common/sign/command/ReadSigningProfileFileCommand.java
org.tizen.common.sign/src/org/tizen/common/sign/command/SignCommand.java [new file with mode: 0755]
org.tizen.common.sign/src/org/tizen/common/sign/model/DeltaListResource.java [new file with mode: 0644]
org.tizen.common.sign/src/org/tizen/common/sign/preferences/SigningProfile.java
org.tizen.common.sign/src/org/tizen/common/sign/preferences/SigningProfileItem.java
org.tizen.common.sign/src/org/tizen/common/sign/preferences/UIMessages.properties
org.tizen.common.sign/src/org/tizen/common/sign/signer/SignatureGenerator.java [new file with mode: 0644]
org.tizen.common.sign/src/org/tizen/common/sign/signer/TizenSigner.java
org.tizen.common.sign/src/org/tizen/common/sign/util/SignatureUtility.java [new file with mode: 0644]
org.tizen.common.sign/src/org/tizen/common/sign/util/SigningProfileUtil.java

index e340406..cbf2ae7 100644 (file)
             name="%page.name">
       </page>
    </extension>
-
+   
+    <extension
+          point="org.tizen.common.prompter">
+       <prompter
+             class="org.tizen.common.sign.SigningPrompter"
+             scope="org.tizen.common.sign.signer.SignatureGenerator">
+       </prompter>
+    </extension>
 </plugin>
diff --git a/org.tizen.common.sign/src/org/tizen/common/sign/SigningPrompter.java b/org.tizen.common.sign/src/org/tizen/common/sign/SigningPrompter.java
new file mode 100644 (file)
index 0000000..fdef1f5
--- /dev/null
@@ -0,0 +1,32 @@
+package org.tizen.common.sign;
+
+import static org.tizen.common.util.SWTUtil.syncExec;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.tizen.common.core.command.CommandCancelException;
+import org.tizen.common.core.command.prompter.SWTPrompter;
+import org.tizen.common.sign.exception.SigningErrorDialog;
+
+public class SigningPrompter extends SWTPrompter {
+
+    @Override
+    public void error(final String message) {
+        final AtomicBoolean isCanceled = new AtomicBoolean( false );
+        
+        syncExec( new Runnable() {
+            @Override
+            public void run() {
+                final SigningErrorDialog dialog = new SigningErrorDialog( message );
+                if ( SigningErrorDialog.CANCEL == dialog.open() ) {
+                    isCanceled.set( true );
+                }
+            }
+        } );
+        
+        if ( isCanceled.get() ) {
+            throw new CommandCancelException();
+        }
+    }
+
+}
index 5a4c7f3..b2266af 100755 (executable)
@@ -111,8 +111,8 @@ extends AbstractCommand<Object>
             return;
         }
         
-        if ( !SigningProfileUtil.hasPassword( authorItem ) ||
-                ( hasDistributor && !SigningProfileUtil.hasPassword( distributorItem ) ) ) {
+        if ( ! authorItem.hasPassword() ||
+                ( hasDistributor && ! distributorItem.hasPassword() ) ) {
             
             ArrayList<UserField> fieldList = new ArrayList<UserField>();
             
@@ -233,11 +233,7 @@ extends AbstractCommand<Object>
     }
 
     protected boolean isValidItem(SigningProfileItem item) {
-        if ( item == null ) {
-            return false;
-        }
-        
-        return SigningProfileUtil.hasKeyLocation( item );
+        return item == null ? false : item.hasKeyLocation();
     }
     
     protected SigningProfileItem getItem(boolean author) {
diff --git a/org.tizen.common.sign/src/org/tizen/common/sign/command/SignCommand.java b/org.tizen.common.sign/src/org/tizen/common/sign/command/SignCommand.java
new file mode 100755 (executable)
index 0000000..257b12a
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Web IDE - sign
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+package org.tizen.common.sign.command;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.lang3.time.StopWatch;
+import org.tizen.common.core.command.ExecutionContext;
+import org.tizen.common.core.command.Executor;
+import org.tizen.common.core.command.Policy;
+import org.tizen.common.core.command.file.FileHandlingCommand;
+import org.tizen.common.core.command.policy.MessagePolicy;
+import org.tizen.common.file.FileHandler;
+import org.tizen.common.file.FileHandler.Attribute;
+import org.tizen.common.sign.exception.CertificationException;
+import org.tizen.common.sign.preferences.SigningProfileItem;
+import org.tizen.common.sign.signer.TizenSigner;
+import org.tizen.common.util.Assert;
+import org.tizen.common.util.StringUtil;
+
+
+public class SignCommand extends FileHandlingCommand<Object> {
+    
+    // active profile name
+    protected String profileName;
+    
+    protected List<SigningProfileItem> profileItems;
+    
+    // categorized profiles
+    protected SigningProfileItem authorProfile = null;
+    protected SigningProfileItem distributor1Profile = null;
+    protected SigningProfileItem distributor2Profile = null;
+    
+    protected boolean bRDS;
+    
+    
+    // Constructor
+    public SignCommand(final String root, final String profileName, final List<SigningProfileItem> profileItems) {
+        this( root, profileName, profileItems, false );
+    }
+
+    public SignCommand(final String root, final String profileName, final List<SigningProfileItem> profileItems, boolean bRDS) {
+        this.path = root;
+        this.profileName = profileName;
+        this.profileItems = profileItems;
+        this.bRDS = bRDS;
+    }
+    
+    protected String getActiveProfileName() {
+        return this.profileName;
+    }
+
+    public void run(final Executor executor, final ExecutionContext context) throws IOException, CertificationException {
+        final FileHandler handler = context.getFileHandler();
+        Assert.notNull( handler );
+        
+        if ( !handler.is( this.path, Attribute.EXISTS ) ) {
+            final Policy policy = context.getPolicy( "nonexist.in.dir.project" );
+            final MessagePolicy messagePolicy = policy.adapt( MessagePolicy.class );
+            
+            messagePolicy.print( context.getPrompter(), "{0} doesn't exist", this.path );
+            return ;
+        }
+        
+        final String appDirPath = (String) handler.get( this.path, Attribute.PATH );
+        
+        // categorize profile
+        categorizeProfiles();
+        
+        StopWatch stopWatch = new StopWatch();
+        try {
+            stopWatch.start();
+            
+            // If option for launch is false, must have author profile.
+            if ( this.authorProfile != null ) {
+                signAuthor( appDirPath, this.authorProfile );
+                signDistributor1( appDirPath, this.distributor1Profile );
+                if ( this.distributor2Profile != null ) {
+                    signDistributor2( appDirPath, this.distributor2Profile );
+                }
+            } else if ( this.distributor1Profile != null ) {
+                // sign developer profile only, no check
+                signDistributor1( appDirPath, this.distributor1Profile );
+            } else {
+                logger.error( "Profiles is not set. Author : {}, Dist1 : {}", this.authorProfile, this.distributor1Profile );
+            }
+        } catch (Exception e) {
+            context.getPrompter().error( e.getMessage() );
+            throw new CertificationException( "Can't create XML Signature file", e );
+        } catch (OutOfMemoryError e) {
+            context.getPrompter().error( e.getMessage() );
+            throw new CertificationException( "Can't create XML Signature file", e );
+        } finally {
+            logger.info( "Elapsed time for sign : {}ms", stopWatch.getTime() );
+        }
+    }
+    
+    private void categorizeProfiles() {
+        for ( SigningProfileItem profileItem : this.profileItems ) {
+            if ( !StringUtil.isEmpty( profileItem.getKeyLocation() ) ) {
+                if ( profileItem.isAuthor() && this.authorProfile == null ) {
+                    this.authorProfile = profileItem;
+                } else if ( this.distributor1Profile == null ) {
+                    this.distributor1Profile = profileItem;
+                } else if ( this.distributor2Profile == null ) {
+                    this.distributor2Profile = profileItem;
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+    
+    private void signAuthor(String appDirPath, SigningProfileItem profileItem) throws Exception {
+        if ( this.bRDS ) {
+            TizenSigner.authorIncrementalSign( appDirPath,
+                getContentFilePath( profileItem ),
+                getContentFilePasswd( profileItem ),
+                getCaCertPath( profileItem ),
+                getRootCertPath( profileItem ) );
+        } else {
+            TizenSigner.authorSign( appDirPath,
+                    getContentFilePath( profileItem ),
+                    getContentFilePasswd( profileItem ),
+                    getCaCertPath( profileItem ),
+                    getRootCertPath( profileItem ) );
+        }
+    }
+    
+    private void signDistributor1(String appDirPath, SigningProfileItem profileItem) throws Exception {
+        if ( this.bRDS ) {
+            TizenSigner.distIncrementalSign( appDirPath,
+                    getContentFilePath( profileItem ),
+                    getContentFilePasswd( profileItem ),
+                    getCaCertPath( profileItem ),
+                    getRootCertPath( profileItem ),
+                    1);
+        } else {
+            TizenSigner.distSign( appDirPath,
+                    getContentFilePath( profileItem ),
+                    getContentFilePasswd( profileItem ),
+                    getCaCertPath( profileItem ),
+                    getRootCertPath( profileItem ),
+                    1);
+        }
+    }
+    
+    private void signDistributor2(String appDirPath, SigningProfileItem profileItem) throws Exception {
+        if ( this.bRDS ) {
+            TizenSigner.dist2IncrementalSignWithParameterCheck( appDirPath,
+                    getContentFilePath( profileItem ),
+                    getContentFilePasswd( profileItem ),
+                    getCaCertPath( profileItem ),
+                    getRootCertPath( profileItem )
+                    );
+        } else {
+            TizenSigner.dist2SignWithParameterCheck( appDirPath,
+                    getContentFilePath( profileItem ),
+                    getContentFilePasswd( profileItem ),
+                    getCaCertPath( profileItem ),
+                    getRootCertPath( profileItem )
+                    );
+        }
+    }
+    
+    private String filterEmptyString(String msg, String content) {
+        String trimmedContent = StringUtil.trim( content );
+        logger.debug( msg, trimmedContent );
+        return ( trimmedContent != null && trimmedContent.isEmpty() ) ? null : trimmedContent;
+    }
+    
+    private String getContentFilePath( final SigningProfileItem profileItem ) {
+        return filterEmptyString( "profile key path : {}" , profileItem.getKeyLocation() );
+    }
+    
+    private String getContentFilePasswd( final SigningProfileItem profileItem ) {
+        return filterEmptyString( "profile key password : {}" , new String( profileItem.getPassword() ) );
+    }
+    
+    private String getCaCertPath( final SigningProfileItem profileItem ) {
+        return filterEmptyString( "profile CA path : {}" , profileItem.getCAPath() );
+    }
+    
+    private String getRootCertPath( final SigningProfileItem profileItem ) {
+        return filterEmptyString( "profile RootCA path : {}" , profileItem.getRootCAPath() );
+    }
+}
diff --git a/org.tizen.common.sign/src/org/tizen/common/sign/model/DeltaListResource.java b/org.tizen.common.sign/src/org/tizen/common/sign/model/DeltaListResource.java
new file mode 100644 (file)
index 0000000..2efb051
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Common - sign
+ * 
+ * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * Jihoon Song <jihoon80.song@samsung.com>
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Kangho Kim <kh5325.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * Contributors:
+ * - S-Core Co., Ltd
+ * 
+ */
+package org.tizen.common.sign.model;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.tizen.common.rds.DeltaResourceInfo;
+import org.tizen.common.util.Assert;
+import org.tizen.common.util.IOUtil;
+import org.tizen.common.sign.util.SignatureUtility;
+
+/**
+ * This class intends to manage a temporary delta information file
+ * 
+ * @author JIhoon Song {@literal<jihoon80.song@samsung.com>}
+ */
+public class DeltaListResource {
+    
+    protected final Logger logger = LoggerFactory.getLogger( getClass() );
+    
+    public static final String FILENAME = ".delta.lst";
+    
+    protected final String[][] typeKeyValue = { // { DeltaType, WritableCharacter }
+            { DeltaResourceInfo.TYPE_MODIFY, "C" }, // created, modified
+            { DeltaResourceInfo.TYPE_DELETE, "D" } // deleted
+    };
+    
+    protected IProject project; // target project
+    protected IContainer cwd; // build resource path
+    protected File listFile;
+    
+    
+    public DeltaListResource(IProject project, IContainer workgingFolder) {
+        Assert.notNull( project );
+        Assert.notNull( workgingFolder );
+        
+        this.project = project;
+        this.cwd = workgingFolder;
+        this.listFile = this.cwd.getLocation().append( FILENAME ).toFile();
+    }
+    
+    /**
+     * create a delta information file.
+     * 
+     * @param deltaInfoList list using {@link org.tizen.common.rds.RdsDeployer#getDelta() }
+     * @throws IOException
+     */
+    public void createListResource(List<DeltaResourceInfo> deltaInfoList) throws IOException {
+        Assert.notNull( deltaInfoList );
+        
+        logger.info( "create delta list for RDS" );
+        
+        OutputStream os = null;
+        try {
+            os = new FileOutputStream( this.listFile );
+            os = new BufferedOutputStream( os );
+            
+            final StringBuilder strBuilder = new StringBuilder();
+            
+            IPath cwdLocation = this.cwd.getLocation();
+            for ( DeltaResourceInfo deltaInfo : deltaInfoList ) {
+                // make relative path
+                final IPath fullPath = new Path( deltaInfo.getFullPath() );
+                final IPath relativePath = fullPath.makeRelativeTo( cwdLocation );
+                if ( ! checkValidPath( relativePath ) ) {
+                    continue;
+                }
+                
+                // make list format ex. "/abc/def/ghi.jklC\n"
+                strBuilder.append( relativePath.toString() );
+                for ( String[] type : this.typeKeyValue ) {
+                    if ( type[0].equals( deltaInfo.getType() ) ) {
+                        strBuilder.append( type[1] );
+                        break;
+                    }
+                }
+                strBuilder.append( '\n' );
+            }
+            
+            logger.debug( strBuilder.toString() );
+            
+            os.write( strBuilder.toString().getBytes() );
+        } finally {
+            IOUtil.tryClose( os );
+        }
+    }
+    
+    protected boolean checkValidPath(IPath path) {
+        Assert.notNull( path );
+        
+        // if the parent path is not equalled
+        String firstSegment = path.segment( 0 );
+        if ( "..".equals( firstSegment ) ) {
+            return false;
+        }
+        
+        // if hidden resource
+        String name = path.lastSegment();
+        if ( name.startsWith( "." ) ) {
+            return false;
+        }
+        
+        // if signature resource
+        if ( SignatureUtility.isSignatureFile( firstSegment ) ) {
+            return false;
+        }
+            
+        return true;
+    }
+    
+    /**
+     * a delta information file getter
+     * @return File. Because this may not exist, it is necessary to check a exist file.
+     */
+    public File getListResource() {
+        return this.listFile;
+    }
+    
+    /**
+     * current working folder getter
+     * @return IContainer is equal to result of {@link BuildResourceManager#getLastWorkingFolder(IProject)}
+     */
+    public IContainer getCurrentWorkingFolder() {
+        return this.cwd;
+    }
+    
+    /**
+     * remove a delta information file
+     * @return true if the file is successfully deleted or if don't neccessary to delete this file
+     */
+    public boolean removeListResource() {
+        Assert.notNull( this.listFile );
+        
+        logger.debug( "remove {}", this.listFile.getAbsolutePath() );
+        
+        return this.listFile.exists() && this.listFile.isFile() ? this.listFile.delete() : true;
+    }
+}
index 339bbb2..9d38153 100644 (file)
 package org.tizen.common.sign.preferences;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
 public class SigningProfile {
 
-       protected String profileName;
-       
-       ArrayList<SigningProfileItem> profileItemList = new ArrayList<SigningProfileItem>();
-       
-       SigningProfileItem authorItem = null;
-       
-       public String getProfileName() {
-               return profileName;
-       }
-       
-       public void setProfileName(String profileName) {
-               this.profileName = profileName;
-       }
-       
-       
-       public void addProfileItem(SigningProfileItem item){
-               profileItemList.add(item);
-       }
-       
-       public void removeProfileItem(SigningProfileItem item){
-               profileItemList.remove(item);
-       }
-       
-       public List<SigningProfileItem> getProfileItemList() {
-               return Collections.unmodifiableList( profileItemList );
-       }
-       
-       public void setAuthorItem(SigningProfileItem authorItem) {
-               this.authorItem = authorItem;
-       }
-       
-       public SigningProfileItem getAuthorItem() {
-               return authorItem;
-       }
-       
+    protected String profileName;
+    protected SigningProfileItem authorItem = null;
+    protected final List<SigningProfileItem> profileItemList = new ArrayList<SigningProfileItem>();
+    
+    
+    public String getProfileName() {
+        return profileName;
+    }
+    
+    public void setProfileName(String profileName) {
+        this.profileName = profileName;
+    }
+    
+    public void addProfileItem(SigningProfileItem item) {
+        this.profileItemList.add( item );
+    }
+    
+    public void removeProfileItem(SigningProfileItem item){
+        this.profileItemList.remove( item );
+    }
+    
+    public List<SigningProfileItem> getProfileItemList() {
+        return Collections.unmodifiableList( this.profileItemList );
+    }
+    
+    public void setAuthorItem(SigningProfileItem authorItem) {
+        this.authorItem = authorItem;
+    }
+    
+    public SigningProfileItem getAuthorItem() {
+        return authorItem;
+    }
+    
+    public SigningProfileItem getDistributorItem(int index) {
+        int size = this.profileItemList.size();
+        if ( index < 0 || index >= size ) {
+            return null;
+        }
+        
+        return this.profileItemList.get( index );
+    }
+    
+    public void initialize(Collection<? extends SigningProfileItem> itemList) {
+        this.setAuthorItem( null );
+        this.profileItemList.clear();
+        
+        for ( SigningProfileItem item : itemList ) {
+            if ( item.isAuthor() ) {
+                this.setAuthorItem( item );
+            } else {
+                this.addProfileItem( item );
+            }
+        }
+    }
 }
index 17b04e4..025ae64 100644 (file)
@@ -134,6 +134,17 @@ SigningProfileItem
         return this.keyLocation;
     }
     
+    public
+    boolean
+    hasKeyLocation()
+    {
+        if ( this.keyLocation == null ) {
+            return false;
+        }
+        
+        return ! this.keyLocation.trim().isEmpty();
+    }
+    
     /**
      * Set key location path
      * 
@@ -222,6 +233,21 @@ SigningProfileItem
         
         return password;
     }
+    
+    /**
+     * Whether a profile item has password or not
+     * 
+     * @param item {@link SigningProfileItem}
+     * @return If has password, return true. otherwise, return false.
+     */
+    public boolean hasPassword() {
+        if ( this.password == null ) {
+            return false;
+        }
+        
+        return ! new String( this.password ).trim().isEmpty();
+    }
+    
     /**
      * Set password for certification file
      * 
index e755cb2..079e2f0 100644 (file)
@@ -4,6 +4,7 @@ org.tizen.common.sign.distrierrordialogtitle=Error generating Distributor Signat
 org.tizen.common.sign.authcerterror=Problem generating Author signature. Aborting Author Signature generation.
 org.tizen.common.sign.checkauthorcertificate=Please check the signing configurations at
 org.tizen.common.sign.preference=Signing Preferences
+org.tizen.common.sign.profileerrormsg=Active signing profile is not set. Please check the signing configurations at <a>{0}</a>
 org.tizen.common.sign.authkeyerror=Problem loading Author private key. Aborting Author Signature generation.
 org.tizen.common.sign.authcertkeyerror=Problem generating Author Signature. Aborting Author Signature generation.
 org.tizen.common.sign.districerterror=Problem generating Distributor signature. Aborting Distributor Signature generation.
diff --git a/org.tizen.common.sign/src/org/tizen/common/sign/signer/SignatureGenerator.java b/org.tizen.common.sign/src/org/tizen/common/sign/signer/SignatureGenerator.java
new file mode 100644 (file)
index 0000000..f96ca71
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Common - sign
+ * 
+ * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * Jihoon Song <jihoon80.song@samsung.com>
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Kangho Kim <kh5325.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * Contributors:
+ * - S-Core Co., Ltd
+ * 
+ */
+package org.tizen.common.sign.signer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.tizen.common.CommonPlugin;
+import org.tizen.common.core.command.ExecutionContext;
+import org.tizen.common.core.command.Policy;
+import org.tizen.common.core.command.policy.SimplePolicy;
+import org.tizen.common.sign.command.ReadSigningProfileFileCommand;
+import org.tizen.common.sign.command.SignCommand;
+import org.tizen.common.sign.preferences.Messages;
+import org.tizen.common.sign.preferences.SigningPreferencePage;
+import org.tizen.common.sign.preferences.SigningProfileItem;
+import org.tizen.common.sign.preferences.UIMessages;
+import org.tizen.common.sign.util.SigningProfileUtil;
+import org.tizen.common.util.StringUtil;
+
+
+/**
+ * This class intends to generate signature files.
+ * but, distributed parts is not integrated yet. 
+ * 
+ * @author JIhoon Song {@literal<jihoon80.song@samsung.com>}
+ */
+public class SignatureGenerator {
+
+    protected final Logger logger = LoggerFactory.getLogger( getClass() );
+    
+    protected ExecutionContext newCtx;
+    
+    protected IPreferenceStore pStore;
+    
+    protected boolean bRDS = false;
+    
+    
+    // Constructor
+    public SignatureGenerator() {
+        this.newCtx =CommonPlugin.getDefault().getExecutor().getContext();
+        this.newCtx.getPolicyRegistry().register( new SimplePolicy( Policy.PRINTOUT_RESULT_SIGNING ) );
+        
+        this.pStore = SigningProfileUtil.getPreferenceStore();
+    }
+    
+    public SigningProfileItem findAuthor(List<SigningProfileItem> profileItems) {
+        for (SigningProfileItem profileItem : profileItems) {
+            if ( profileItem.isAuthor() ) {
+                if ( !StringUtil.isEmpty( profileItem.getKeyLocation() ) ) {
+                    return profileItem;
+                }
+            }
+        }
+        
+        return null;
+    }
+    
+    public boolean hasAuthor(List<SigningProfileItem> profileItems) {
+        return findAuthor( profileItems ) != null;
+    }
+    
+    protected boolean getInsertSignatureOption() {
+        return this.pStore.getBoolean( SigningPreferencePage.testCertKey );
+    }
+    
+    protected String getActiveProfileName() {
+        return this.pStore.getString( SigningPreferencePage.defaultProfileKey );
+    }
+    
+    /**
+     * Load activated profile items with a developer profile from profiles.xml
+     * If cannot find a key location in the author certificate, pop up the error dialog with a preference link.
+     * 
+     * @return If profile items are nothing, return a developer profile item only. otherwise, return default profile items with a developer profile item
+     * @throws IOException
+     */
+    public List<SigningProfileItem> loadProfiles() throws IOException {
+        List<SigningProfileItem> profileItems = new ArrayList<SigningProfileItem>();
+        
+        // Always add a developer certificate first because must be "signature1.xml"
+        profileItems.add( SigningProfileUtil.createDeveloperItem() );
+        
+        while ( getInsertSignatureOption() ) {
+            // read profiles
+            final ReadSigningProfileFileCommand readProfile =
+                    new ReadSigningProfileFileCommand( SigningProfileUtil.getProfilesPath(), getActiveProfileName() );
+            CommonPlugin.getDefault().getExecutor().execute( readProfile );
+            
+            // check requirements in profile
+            if ( hasAuthor( readProfile.getProfileItems() ) ) {
+                profileItems.addAll( readProfile.getProfileItems() );
+                break;
+            }
+            
+            // interact user for setting profiles
+            final String error = Messages.bind( UIMessages.getString( "org.tizen.common.sign.profileerrormsg" ),
+                    UIMessages.getString("org.tizen.common.sign.preference") );
+            this.newCtx.getPrompter().error( error );
+            
+            // retry reading
+        }
+        
+        return profileItems;
+    }
+    
+    public void sign(String path, List<SigningProfileItem> profileItems) {
+        final SignCommand command = new SignCommand( path, getActiveProfileName(), profileItems, isRDSMode() );
+        command.setExcludes( new String[] { ".*", "*~" } );
+        CommonPlugin.getDefault().getExecutor().execute( this.newCtx, command );
+    }
+    
+    public void setRDSMode(boolean bRDS) {
+        this.bRDS = bRDS;
+    }
+    
+    public boolean isRDSMode() {
+        return this.bRDS;
+    }
+}
index baf8cf3..c3557b5 100644 (file)
@@ -84,6 +84,16 @@ public class TizenSigner {
         HashingSigning.DistributorSignature(targetDir, distP12Path, distPass, distCAPath, distRootPath, distNumber);
     }
     
+    public static void authorIncrementalSign(String targetDir, String authorP12Path, String authorPass, String authorCAPath, String rootCaPath) throws Exception{
+        checkNullParameters(targetDir, authorP12Path, authorPass);
+        HashingSigning.AuthorSignatureRDS(targetDir, authorP12Path, authorPass, authorCAPath, null);
+    }
+    
+    public static void distIncrementalSign(String targetDir, String distP12Path, String distPass, String distCAPath, String distRootPath, int distNumber) throws Exception{
+        checkNullParameters(targetDir, distP12Path, distPass);
+        HashingSigning.DistributorSignatureRDS(targetDir, distP12Path, distPass, distCAPath, distRootPath, distNumber);
+    }
+    
     private static void checkNullParameters(String targetDir, String p12Path, String pass) throws IllegalArgumentException{
         String emptyParameter = null;
         if(StringUtil.isEmpty(targetDir)) {
@@ -110,4 +120,14 @@ public class TizenSigner {
             distSign(targetDir, dist2P12Path, dist2Pass, dist2CAPath, dist2RootPath, 2);
         }
     }
+    
+    public static void dist2IncrementalSignWithParameterCheck(String targetDir, String dist2P12Path, String dist2Pass, String dist2CAPath, String dist2RootPath) throws Exception{
+        if(!StringUtil.isEmpty(dist2P12Path) && !StringUtil.isEmpty(dist2Pass)) {
+            if(StringUtil.isEmpty(dist2CAPath) || StringUtil.isEmpty(dist2RootPath)) {
+                dist2CAPath = null;
+                dist2RootPath = null;
+            }
+            distIncrementalSign(targetDir, dist2P12Path, dist2Pass, dist2CAPath, dist2RootPath, 2);
+        }
+    }
 }
diff --git a/org.tizen.common.sign/src/org/tizen/common/sign/util/SignatureUtility.java b/org.tizen.common.sign/src/org/tizen/common/sign/util/SignatureUtility.java
new file mode 100644 (file)
index 0000000..639014d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Common - sign
+ * 
+ * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * Jihoon Song <jihoon80.song@samsung.com>
+ * Kangho Kim <kh5325.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.
+ * 
+ * Contributors:
+ * - S-Core Co., Ltd
+ * 
+ */
+
+package org.tizen.common.sign.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class SignatureUtility {
+
+    public static final String AUTHOR_PREFIX = "author-signature"; //$NON-NLS-1$
+    public static final String DISTRIBUTOR_PREFIX = "signature"; //$NON-NLS-1$
+    public static final String PERIOD = "."; //$NON-NLS-1$
+    public static final String EXTENSION = "xml"; //$NON-NLS-1$
+    
+    private static final String regExp = "(" //$NON-NLS-1$
+            + DISTRIBUTOR_PREFIX
+            + "(1|2|3|4|5|6|7|8|9)(\\d)*" //$NON-NLS-1$
+            + PERIOD + EXTENSION
+            + ")"; //$NON-NLS-1$
+    
+    private static final Pattern pattern = Pattern.compile( regExp );
+    
+    
+    public static boolean isSignatureFile(String name) {
+        if ( isAuthorSignatureFile( name ) ) {
+            return true;
+        }
+        
+        return isDistributorSignatureFile( name );
+    }
+    
+    public static boolean isAuthorSignatureFile(String name) {
+        return name.equalsIgnoreCase( AUTHOR_PREFIX + PERIOD + EXTENSION );
+    }
+    
+    public static boolean isDistributorSignatureFile(String name) {
+        final Matcher matcher = pattern.matcher( name );
+        return matcher.matches();
+    }
+
+}
\ No newline at end of file
index d0cec50..419e660 100644 (file)
@@ -504,27 +504,6 @@ public class SigningProfileUtil
         return null;
     }
     
-    public static boolean hasKeyLocation( final SigningProfileItem item ) {
-        Assert.notNull( item );
-        
-        final String keyLocation = item.getKeyLocation();
-        
-        return ( keyLocation == null ) ? false : !keyLocation.trim().isEmpty();
-    }
-    
-    /**
-     * Whether a profile item has password or not 
-     * @param item {@link SigningProfileItem}
-     * @return If has password, return true. otherwise, return false.
-     */
-    public static boolean hasPassword( final SigningProfileItem item ) {
-        Assert.notNull( item );
-        
-        final char[] password = item.getPassword();
-        
-        return ( password == null ) ? false : !( new String( password ).trim().isEmpty() );
-    }
-    
     /**
      * Getter for element by profile name
      * @param doc Document