Q & A. IV

This guy asked me through linkedin.

I saw you in EMC community and wanted your advice on xCP 2.2 workflows. We have xCP 1.6 workflows and currently planning to re-design them to xCP 2.2 and having below queries ..

1) We have a custom document object type called cus_enterpirse which inherits from dm_document. We are using this type as package in current xCP 1.6 workflow. Can we use the same object type in xCP 2.2 environment (like adopting cus_enterprise ) for workflows ?

2) Will there be any conflicts/issues for existing workflows in xCP 1.6 environment if we adopt the custom type in xCP designer and install the application using xCP 2.2 environment ? Also we wanted to run both xCP 1.6 and xCP 2.2 workflows parallelly for same data model as packages, Will this have any impact

3) We heard that we cannot use the same data model in xCP 1.6 and xCP 2.2 environment and we need to create new data model for workflows and then use it in xCP 2.2 workflows. Is that correct?

Sukumar, first of all, you seem to be a very good EMC customer – once you already bought a stillborn product (xCP), now you are taking a part in beta-testing (xCP2), and in my opinion EMC support must make every effort to help you in your project 🙂

Anyway, type adoption feature does work (we were able to make xCP2 work with composer types and webtop work with xCP2 workflows) but there are some glitches you would like to know:

  • xCP Designer behaves very strange with adopted types: removing adopted type from project and further installing this project causes removing adopted type from repository – be careful with this “feature” (yeap, EMC considers this bug as feature request)
  • interoperability between xCP2 and other applications, which was promised by EMC in xCP2.1, was nothing but fail:
  • Yes, xCP2 workflows use another model (no aliassets, no custom methods, process variables are stored differently), technically this means that you should either dot not work with workflows through old application (for example, xCP2 does display tasks only for it’s workflows) or implement custom adapter, for example below is our utility class that allows to work with different models of process variables (it assumes that there is some naming convention for process variables):
    /**
     * @author Andrey B. Panfilov <andrew@panfilov.tel>
     */
    public class ProcessVariableUtils {
    
        public ProcessVariableUtils() {
            super();
        }
    
        public static Object getValue(IDfWorkitemEx workitem, String variableName)
            throws DfException {
            int dotIndex = variableName.indexOf(".");
            if (dotIndex < 0) {
                return getProcessVariableValueInternal(workitem, variableName);
            }
            for (String candidate : structuredToPrimitive(variableName)) {
                try {
                    return getProcessVariableValueInternal(workitem, candidate);
                } catch (ProcessVariableNotFoundException ex) {
                    // pass
                } catch (ProcessVariableTypeNullIdException ex) {
                    // pass
                }
            }
            String setting = variableName.substring(0, dotIndex);
            String parameter = variableName.substring(dotIndex + 1,
                    variableName.length());
            return workitem.getStructuredDataTypeAttrValue(setting, parameter);
        }
    
        private static Object getProcessVariableValueInternal(
                IDfWorkitemEx workitem, String variableName) throws DfException {
            return getNonProxied(workitem).getPrimitiveVariableValue(variableName);
        }
    
        public static Object getValue(IDfWorkflowEx workflow, String variableName)
            throws DfException {
            int dotIndex = variableName.indexOf(".");
            if (dotIndex < 0) {
                return getProcessVariableValueInternal(workflow, variableName);
            }
            for (String candidate : structuredToPrimitive(variableName)) {
                try {
                    return getProcessVariableValueInternal(workflow, candidate);
                } catch (ProcessVariableNotFoundException ex) {
                    // pass
                } catch (ProcessVariableTypeNullIdException ex) {
                    // pass
                }
            }
            String setting = variableName.substring(0, dotIndex);
            String parameter = variableName.substring(dotIndex + 1,
                    variableName.length());
            return workflow.getStructuredDataTypeAttrValue(setting, parameter);
        }
    
        private static Object getProcessVariableValueInternal(
                IDfWorkflowEx workflow, String variableName) throws DfException {
            return getNonProxied(workflow).getPrimitiveVariableValue(variableName);
        }
    
        public static void setValue(IDfWorkitemEx workitem, String variableName,
                Object value) throws DfException {
            int dotIndex = variableName.indexOf(".");
            if (dotIndex < 0) {
                setProcessVariableValueInternal(workitem, variableName, value);
                return;
            }
            for (String candidate : structuredToPrimitive(variableName)) {
                try {
                    setProcessVariableValueInternal(workitem, candidate, value);
                    return;
                } catch (ProcessVariableNotFoundException ex) {
                    // pass
                } catch (ProcessVariableTypeNullIdException ex) {
                    // pass
                }
            }
            String setting = variableName.substring(0, dotIndex);
            String parameter = variableName.substring(dotIndex + 1,
                    variableName.length());
            workitem.setStructuredDataTypeAttrValue(setting, parameter, value);
        }
    
        private static void setProcessVariableValueInternal(IDfWorkitemEx workitem,
                String variableName, Object value) throws DfException {
            getNonProxied(workitem).setPrimitiveObjectValue(variableName, value);
        }
    
        public static void setValue(IDfWorkflowEx workflow, String variableName,
                Object value) throws DfException {
            int dotIndex = variableName.indexOf(".");
            if (dotIndex < 0) {
                setProcessVariableValueInternal(workflow, variableName, value);
                return;
            }
            for (String candidate : structuredToPrimitive(variableName)) {
                try {
                    setProcessVariableValueInternal(workflow, candidate, value);
                    return;
                } catch (ProcessVariableNotFoundException ex) {
                    // pass
                } catch (ProcessVariableTypeNullIdException ex) {
                    // pass
                }
            }
            String setting = variableName.substring(0, dotIndex);
            String parameter = variableName.substring(dotIndex + 1,
                    variableName.length());
            workflow.setStructuredDataTypeAttrValue(setting, parameter, value);
        }
    
        private static void setProcessVariableValueInternal(IDfWorkflowEx workflow,
                String variableName, Object value) throws DfException {
            getNonProxied(workflow).setPrimitiveObjectValue(variableName, value);
        }
    
        public static Object[] getValues(IDfWorkitemEx workitem, String variableName)
            throws DfException {
            int dotIndex = variableName.indexOf(".");
            if (dotIndex < 0) {
                return getProcessVariableValuesInternal(workitem, variableName);
            }
            for (String candidate : structuredToPrimitive(variableName)) {
                try {
                    return getProcessVariableValuesInternal(workitem, candidate);
                } catch (ProcessVariableNotFoundException ex) {
                    // pass
                } catch (ProcessVariableTypeNullIdException ex) {
                    // pass
                }
            }
            String setting = variableName.substring(0, dotIndex);
            String parameter = variableName.substring(dotIndex + 1,
                    variableName.length());
            return workitem.getStructuredDataTypeAttrValues(setting, parameter);
        }
    
        private static Object[] getProcessVariableValuesInternal(
                IDfWorkitemEx workitem, String variableName) throws DfException {
            try {
                workitem = getNonProxied(workitem);
                Method method = ReflectionUtils.getMethod(workitem.getClass(),
                        "getRepeatingPrimitiveVariableValues", String.class);
                if (method != null) {
                    List result = (List) method.invoke(workitem, variableName);
                    if (result == null) {
                        return new Object[] {};
                    }
                    return result.toArray(new Object[result.size()]);
                }
                throw new ProcessVariableNotFoundException(
                        "getRepeatingPrimitiveVariableValues", variableName);
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable t = ex.getTargetException();
                if (t instanceof DfException) {
                    throw (DfException) t;
                }
                throw new RuntimeException(ex);
            }
        }
    
        public static Object[] getValues(IDfWorkflowEx workflow, String variableName)
            throws DfException {
            int dotIndex = variableName.indexOf(".");
            if (dotIndex < 0) {
                return getProcessVariableValuesInternal(workflow, variableName);
            }
            for (String candidate : structuredToPrimitive(variableName)) {
                try {
                    return getProcessVariableValuesInternal(workflow, candidate);
                } catch (ProcessVariableNotFoundException ex) {
                    // pass
                } catch (ProcessVariableTypeNullIdException ex) {
                    // pass
                }
            }
            String setting = variableName.substring(0, dotIndex);
            String parameter = variableName.substring(dotIndex + 1,
                    variableName.length());
            return workflow.getStructuredDataTypeAttrValues(setting, parameter);
        }
    
        private static Object[] getProcessVariableValuesInternal(
                IDfWorkflowEx workflow, String variableName) throws DfException {
            try {
                workflow = getNonProxied(workflow);
                Method method = ReflectionUtils.getMethod(workflow.getClass(),
                        "getRepeatingPrimitiveVariableValues", String.class);
                if (method != null) {
                    List result = (List) method.invoke(workflow, variableName);
                    if (result == null) {
                        return new Object[] {};
                    }
                    return result.toArray(new Object[result.size()]);
                }
                throw new ProcessVariableNotFoundException(
                        "getRepeatingPrimitiveVariableValues", variableName);
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable t = ex.getTargetException();
                if (t instanceof DfException) {
                    throw (DfException) t;
                }
                throw new RuntimeException(ex);
            }
        }
    
        public static void setValues(IDfWorkitemEx workitem, String variableName,
                Object[] values) throws DfException {
            int dotIndex = variableName.indexOf(".");
            if (dotIndex < 0) {
                setProcessVariableValuesInternal(workitem, variableName, values);
                return;
            }
            for (String candidate : structuredToPrimitive(variableName)) {
                try {
                    setProcessVariableValuesInternal(workitem, candidate, values);
                    return;
                } catch (ProcessVariableNotFoundException ex) {
                    // pass
                } catch (ProcessVariableTypeNullIdException ex) {
                    // pass
                }
            }
            String setting = variableName.substring(0, dotIndex);
            String parameter = variableName.substring(dotIndex + 1,
                    variableName.length());
            workitem.setStructuredDataTypeAttrValues(setting, parameter, values);
        }
    
        private static void setProcessVariableValuesInternal(
                IDfWorkitemEx workitem, String variableName, Object[] values)
            throws DfException {
            try {
                workitem = getNonProxied(workitem);
                Method method = ReflectionUtils.getMethod(workitem.getClass(),
                        "setRepeatingPrimitiveObjectValues", String.class,
                        List.class);
                if (method != null) {
                    method.invoke(workitem, variableName, Arrays.asList(values));
                    return;
                }
                throw new ProcessVariableNotFoundException(
                        "setRepeatingPrimitiveObjectValues", variableName);
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable t = ex.getTargetException();
                if (t instanceof DfException) {
                    throw (DfException) t;
                }
                throw new RuntimeException(ex);
            }
        }
    
        public static void setValues(IDfWorkflowEx workflow, String variableName,
                Object[] values) throws DfException {
            int dotIndex = variableName.indexOf(".");
            if (dotIndex < 0) {
                setProcessVariableValuesInternal(workflow, variableName, values);
                return;
            }
            for (String candidate : structuredToPrimitive(variableName)) {
                try {
                    setProcessVariableValuesInternal(workflow, candidate, values);
                    return;
                } catch (ProcessVariableNotFoundException ex) {
                    // pass
                } catch (ProcessVariableTypeNullIdException ex) {
                    // pass
                }
            }
            String setting = variableName.substring(0, dotIndex);
            String parameter = variableName.substring(dotIndex + 1,
                    variableName.length());
            workflow.setStructuredDataTypeAttrValues(setting, parameter, values);
        }
    
        private static void setProcessVariableValuesInternal(
                IDfWorkflowEx workflow, String variableName, Object[] values)
            throws DfException {
            try {
                workflow = getNonProxied(workflow);
                Method method = ReflectionUtils.getMethod(workflow.getClass(),
                        "setRepeatingPrimitiveObjectValues", String.class,
                        List.class);
                if (method != null) {
                    method.invoke(workflow, variableName, Arrays.asList(values));
                    return;
                }
                throw new ProcessVariableNotFoundException(
                        "setRepeatingPrimitiveObjectValues", variableName);
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable t = ex.getTargetException();
                if (t instanceof DfException) {
                    throw (DfException) t;
                }
                throw new RuntimeException(ex);
            }
        }
    
        private static List<String> structuredToPrimitive(String variableName) {
            List<String> candidates = new ArrayList<String>(2);
            candidates.add(variableName.replace('.', '_').replace('/', '_'));
            candidates.add(variableName.replace('.', '_').replace('/', '_')
                    .toLowerCase());
            return candidates;
        }
    
        private static IDfWorkitemEx getNonProxied(IDfWorkitemEx workitemEx) {
            if (workitemEx instanceof IDfWorkitemExWrapper) {
                workitemEx = (IDfWorkitemEx) ((IDfWorkitemExWrapper) workitemEx)
                        .getWrappedObject();
            }
            if (workitemEx instanceof IProxyHandler) {
                return (IDfWorkitemEx) ((IProxyHandler) workitemEx)
                        .____getImp____();
            }
            return workitemEx;
        }
    
        private static IDfWorkflowEx getNonProxied(IDfWorkflowEx workflowEx) {
            if (workflowEx instanceof IProxyHandler) {
                return (IDfWorkflowEx) ((IProxyHandler) workflowEx)
                        .____getImp____();
            }
            return workflowEx;
        }
    
    }
    
    

12 thoughts on “Q & A. IV

  1. Dear Andrey,

    Thanks a lot for your advise and explaining the details in brief. Really appreciate your help..

    Also i have two more queries ..Sorry if i’m asking too much 😦

    1) Once you have adopted a type in composer and installed it, were you able to create instance of that type through other clients like webtop and DA. Because in my case i’m facing some aspect related issue which creating the object through webtop and it neither allows me to create nor open the existing document instances of that type..Looks like a bug and still SR is pending with EMC about this issue

    2) We have TBO and there are methods like doSave(), doCheckin() and doCheck() were overridden and customized extensively. Will be face any issues related to TBO once we adopt that specific type and then install through xCP designer ( Say that we don’t have any Business Events )

    Like

  2. When working with xCP types (and adopted types as well) you may face with to common errors:
    DFC_BOF_ASPECT_INVALID_SET – the root cause of this error is described in DFC_BOF_ASPECT_INVALID_SET error and XCP types, this error was resolved by EMC through dirty hack in DFC – all what you need in update DFC library in your application(s) to the latest patchset
    various ClassNotFoundException/NoClassDefFoundError errors – here you need to be patient and put all missing libraries into your application (I saw some related posts in ECN)

    Even you don’t use “business events” feature, xCP aspects could break your TBOs, some examples:

    changing lifecycle state in TBO like:

    @Override
    protected synchronized void doSave(boolean keepLock, String versionLabels,
            Object[] extendedArgs) throws DfException {
        super.doSave(keepLock, versionLabels, extendedArgs);
        if (somecondition) {
            promote("new state", true, false);
        }
    }
    

    does not work anymore because due to aspects doSave() method is executed within transaction and the correct code now is:

    @Override
    protected synchronized void doSave(boolean keepLock, String versionLabels,
            Object[] extendedArgs) throws DfException {
        super.doSave(keepLock, versionLabels, extendedArgs);
        if (somecondition) {
            promote("new state", true, false);
        }
    }
    
    @Override
    public void promote(final String state, final boolean override,
            final boolean fTestOnly) throws DfException {
        ISession session = getObjectSession();
        if (!session.isTransactionActive()) {
            super.promote(state, override, fTestOnly);
            return;
        }
        IDfTransactionObserver observer = new PostCommitObserver() {
    
            @Override
            public void onPostCommit(IDfSession iDfSession, int i)
                throws DfException {
                promote(state, override, fTestOnly);
            }
    
        };
        session.getTransaction().getObservable().addObserver(observer);
    }
    
    private abstract class PostCommitObserver implements IDfTransactionObserver {
    
        protected PostCommitObserver() {
            super();
        }
    
        @Override
        public void onPreCommit(IDfSession iDfSession) throws DfException {
    
        }
    
        @Override
        public void onPreRollback(IDfSession iDfSession) throws DfException {
    
        }
    
        @Override
        public void onPostRollback(IDfSession iDfSession, int i)
            throws DfException {
    
        }
    }
    
    

    Another example – we would like to set default folder for object through TBO:

    @Override
    protected synchronized void doSave(boolean keepLock, String versionLabels,
            Object[] extendedArgs) throws DfException {
        // unlinking from all folders
        for (int i = getFolderIdCount() - 1; i >= 0; i--) {
            unlink(getFolderId(i).getId());
        }
        // linking to default folder
        link(getDefaultFolderPath());
        super.doSave(keepLock, versionLabels, extendedArgs);
    }
    

    Now that code does not work properly because xCP aspects also define default folder for object, and correct TBO code in this case is:

    @Override
    protected synchronized void doSave(boolean keepLock, String versionLabels,
            Object[] extendedArgs) throws DfException {
        // unlinking from all folders
        for (int i = getFolderIdCountEx() - 1; i >= 0; i--) {
            unlink(getFolderIdEx(i).getId());
        }
        // linking to default folder
        link(getDefaultFolderPath());
        super.doSave(keepLock, versionLabels, extendedArgs);
    }
    

    Like

  3. Excellent..That’s great information and unfortunately EMC didn’t document it any where about the issues with aspects and impact on existing customizations

    In our case, while we create any document for types which were already adopted, it throws below error

    DfException:: THREAD: Timer-23; MSG: ; ERRORCODE: ff; NEXT: null
        at com.emc.xcp.runtime.aspect.impl.Utils.ThrowDfcException(Utils.java:33)
        at com.emc.xcp.runtime.aspect.impl.DataTypeAspectUtils.xcpSave(DataTypeAspectUtils.java:86)
        at com.emc.xcp.runtime.aspect.impl.DataTypeAspectUtils.xcpSave(DataTypeAspectUtils.java:30)
        at com.emc.xcp.runtime.aspect.impl.DataTypeAspect.doSave(DataTypeAspect.java:35)
        at com.documentum.services.collaboration.impl.TopicAspect.doSave(Unknown Source)
        at com.documentum.fc.client.DfPersistentObject.saveEx(DfPersistentObject.java:913)
        at com.documentum.fc.client.DfPersistentObject.save(DfPersistentObject.java:908)
        at com.documentum.services.collaboration.impl.TopicAspect___PROXY.save(TopicAspect___PROXY.java)
        at com.documentum.operations.nodeactions.inbound.DfCheckinObject.checkin(DfCheckinObject.java:235)
        at com.documentum.operations.nodeactions.inbound.DfCheckinObject.execute(DfCheckinObject.java:39)
        at com.documentum.operations.steps.impl.OperationStep.executeStep(OperationStep.java:163)
        at com.documentum.operations.steps.impl.OperationStep.execute(OperationStep.java:41)
        at com.documentum.operations.impl.OperationExecutionEngine.execute(OperationExecutionEngine.java:51)
        at com.documentum.operations.DfOperation.execute(DfOperation.java:401)
        at com.documentum.operations.inbound.impl.InboundOperation.execute(InboundOperation.java:104)
        at com.documentum.operations.inbound.DfImportOperation.execute(DfImportOperation.java:96)
        at com.documentum.web.contentxfer.DFCOperationSupport.execute(DFCOperationSupport.java:61)
        at com.documentum.web.contentxfer.ContentTransferService.execute(ContentTransferService.java:377)
        at com.documentum.web.contentxfer.JobAdapter.execute(JobAdapter.java:108)
        at com.documentum.job.async.AsyncJobManager$AsyncTimerJob.executeJob(AsyncJobManager.java:236)
        at com.documentum.job.async.AsyncJobManager$AsyncTimerJob.run(AsyncJobManager.java:215)
        at java.util.TimerThread.mainLoop(Unknown Source)
        at java.util.TimerThread.run(Unknown Source)
    Caused by: java.lang.IllegalArgumentException: urn must not be null or blank
        at com.emc.xcp.artifactmanager.util.UrnUtils.getNamespace(UrnUtils.java:126)
    

    Like

  4. What is the result of following DQL:

    select namespace from xcp_artifact_bundle
    where any installedobjectid in (
    select r_object_id from dm_type
    where name='<type name you are trying to import>')
    

    ?

    Like

  5. It gave result as tst12. This is the namespace i gave for this xCP project. When i try to create empty object from DQL through DQMan its working. Where as if i try from either webtop or DA DQL it throws error. Since DQMan is not invoking the DFC( and hence no TBO, no Aspects) and it’s getting created.

    Like

  6. It seems the the root cause of “urn must not be null or blank” error is a fact that xCP layer is unable to find a corresponding xCP artifact for object type you are trying to manipulate with, and I would say that possible reasons are:
    * you are trying to manipulate with subtype of adopted type and this subtype is not adopted (i.e. aspects are attached to this subtype but subtype is not registered in xcp_artifact_bundle)
    * supertype (if exists) of your type is not adopted
    * your application contains outdated xCP2 libraries (bpm_infra-2.x.x.x, com.emc.xcp.artifactmanager-2.x.x.x, etc) as the result of previous experiments
    * wrong naming convention – name of adopted type must not start with xCP namespace (seems not your case)
    * buggy xCP version

    Like

  7. Hello sukumarramadugu,

    You can also post your xCP quires to EMC-xCP official forum so it will be reviewed and reply by many xCP experts.

    Like

  8. Pingback: My apologize for the last comment | Documentum in a (nuts)HELL
  9. Hi Andrey, Today the issue was resolved and thanks a lot for your inputs. As you guessed, i have adopted a type but not its sub type and when i try to create a sub type through webtop/DA, it is throwing this error. So i have adopted all the sub types in xCP designer and then installed which has resolved the issue. Only trick is that once a type gets adopted, xCp designer doesnt even show the sub types of the Adopted type. So we need to remove the type entry in xcp_artifact_bundle and then Adopt the sub types as well and then install.

    This will resolve the issue….

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s