cancel
Showing results for 
Search instead for 
Did you mean: 

Child association and web client

skank
Champ in-the-making
Champ in-the-making
Hello,

first, I apologize for my bad English  Smiley Happy

I have created a custom model with a child association between two documents :

    <types>
        <type name="az:doc">
            <parent>cm:content</parent>
            <properties>
                <property name="az:version">
                    <type>d:text</type>
                </property>
                <property name="az:date">
                    <type>d:date</type>
                </property>
            </properties>

            <associations>
                <child-association name="az:azerty">
                    <source>
                        <mandatory>true</mandatory>
                        <many>false</many>
                    </source>
                    <target>
                        <class>az:model</class>
                        <mandatory>false</mandatory>
                        <many>false</many>
                    </target>
                    <duplicate>false</duplicate>
                    <propagateTimestamps>true</propagateTimestamps>
                </child-association>
            </associations>
           
            <mandatory-aspects>
                <aspect>cm:versionable</aspect>
                <aspect>cm:auditable</aspect>
            </mandatory-aspects>
        </type>
       
        <type name="az:model">
            <parent>cm:content</parent>
            <properties>
                <property name="az:fr">
                    <type>d:text</type>
                </property>
            </properties>
        </type>
    </types>

After that, I have configured the web-client-config-custom :

    <config evaluator="node-type" condition="az:doc">
        <property-sheet>
            <show-property name="az:version" show-in-edit-mode="true" />
            <show-property name="az:date" show-in-edit-mode="true" />
            <show-child-association name="az:azerty" component-generator="ChildAssociationGenerator" />
        </property-sheet>
    </config>

    <config evaluator="node-type" condition="az:model">
        <property-sheet>
            <show-property name="az:fr" />
            <show-child-association name="az:azerty" show-in-edit-mode="false" />
        </property-sheet>
    </config>

But now, I'm a bit confused, because I wanted to show my az:model in the web client (like the others files), and that doesn't appears, because it is the child of my az:doc, and not of the folder.

So this is my question : is there any possibility to show on the web client my az:model like the other files ?

Thanks for the help.
5 REPLIES 5

jpotts
World-Class Innovator
World-Class Innovator
You should see your child associations on the property details for an instance of az:doc but you will not see instances of az:model from a web client browse space view. You'd have to do a customization to get that to work. In the web client, only the child associations of the given cm:folder (or its subtype) are displayed in the list of documents.

Jeff

skank
Champ in-the-making
Champ in-the-making
Thank you for your reply. I've done a customization like you said : I've overrided the BrowseBean, and now I can see my az:model, next to my az:doc.  Smiley Happy

laurent1050
Champ in-the-making
Champ in-the-making
Hi skank,

I'm interested on how you've overrided the BrowseBean.
Could you give your config as an example ?

I'm trying to do the same thing for a day, and I'm in despair  :?

Thanks
Laurent

skank
Champ in-the-making
Champ in-the-making
No problem  Smiley Happy

Here is my faces-config-custom.xml (in WEB-INF) :

<managed-bean>
      <description>
         The bean that holds folder browse state.
      </description>
      <managed-bean-name>BrowseBean</managed-bean-name>
      <managed-bean-class>(my package).CustomBrowseBean</managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>
      <managed-property>
         <property-name>navigator</property-name>
         <value>#{NavigationBean}</value>
      </managed-property>
      <managed-property>
         <property-name>nodeService</property-name>
         <value>#{NodeService}</value>
      </managed-property>
      <managed-property>
         <property-name>searchService</property-name>
         <value>#{SearchService}</value>
      </managed-property>
      <managed-property>
         <property-name>lockService</property-name>
         <value>#{LockService}</value>
      </managed-property>
      <managed-property>
         <property-name>dictionaryService</property-name>
         <value>#{DictionaryService}</value>
      </managed-property>
      <managed-property>
         <property-name>fileFolderService</property-name>
         <value>#{FileFolderService}</value>
      </managed-property>
</managed-bean>

I've copied the  source code of BrwoseBean in my CustomBrowseBean. Then, I've added this in the queryBrowseNodes method (line 930) :

   private void queryBrowseNodes(String parentNodeId)
   {
      long startTime = 0;
      if (logger.isDebugEnabled())
         startTime = System.currentTimeMillis();

      UserTransaction tx = null;
      try
      {
         FacesContext context = FacesContext.getCurrentInstance();
         tx = Repository.getUserTransaction(context, true);
         tx.begin();

         NodeRef parentRef;
         if (parentNodeId == null)
         {
            // no specific parent node specified - use the root node
            parentRef = this.getNodeService().getRootNode(Repository.getStoreRef());
         }
         else
         {
            // build a NodeRef for the specified Id and our store
            parentRef = new NodeRef(Repository.getStoreRef(), parentNodeId);
         }
         List<FileInfo> children = this.getFileFolderService().list(parentRef);
         this.containerNodes = new ArrayList<Node>(children.size());
         this.contentNodes = new ArrayList<Node>(children.size());

         // in case of dynamic config, only lookup once
         Set<NodeEventListener> nodeEventListeners = getNodeEventListeners();

         for (FileInfo fileInfo : children)
         {
            // create our Node representation from the NodeRef
            NodeRef nodeRef = fileInfo.getNodeRef();

            // find it's type so we can see if it's a node we are interested in
            QName type = this.getNodeService().getType(nodeRef);

            // make sure the type is defined in the data dictionary
            TypeDefinition typeDef = this.getDictionaryService().getType(type);

            if (typeDef != null)
            {
               MapNode node = null;

               // look for File content node
               if (this.getDictionaryService().isSubClass(type, ContentModel.TYPE_CONTENT))
               {
                  // create our Node representation
                  node = new MapNode(nodeRef, this.getNodeService(), fileInfo.getProperties());
                  setupCommonBindingProperties(node);

                  this.contentNodes.add(node);

                  logger.debug("File Content Node "+node.getName());

                  /**************************************************************
                   *                Beginning of the added part               *
                   **************************************************************/


                   if(type.equals(my custom type){
                       if(this.nodeService.getChildAssocs(nodeRef) != null){
                           for(ChildAssociationRef child:this.nodeService.getChildAssocs(nodeRef)){
                               MapNode childNode = new MapNode( child.getChildRef(),
                                                                this.getNodeService(),
                                                                this.nodeService.getProperties(child.getChildRef()));
                               setupCommonBindingProperties(childNode);
                               this.contentNodes.add(childNode);
                               logger.debug("PR Node : "+childNode.getName());
                           }
                       }
                   }

                  /**************************************************************
                   *                end of the added part                       *
                   **************************************************************/
               }
               // look for Space folder node
               else if (this.getDictionaryService().isSubClass(type, ContentModel.TYPE_FOLDER) == true &&
                        this.getDictionaryService().isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER) == false)
               {
                  // create our Node representation
                  node = new MapNode(nodeRef, this.getNodeService(), fileInfo.getProperties());
                  node.addPropertyResolver("icon", this.resolverSpaceIcon);
                  node.addPropertyResolver("smallIcon", this.resolverSmallIcon);

                  this.containerNodes.add(node);
               }
               // look for File Link object node
               else if (ApplicationModel.TYPE_FILELINK.equals(type))
               {
                  // create our File Link Node representation
                  node = new MapNode(nodeRef, this.getNodeService(), fileInfo.getProperties());
                  // only display the user has the permissions to navigate to the target of the link
                  @SuppressWarnings("element-type-mismatch")
                  NodeRef destRef = (NodeRef)node.getProperties().get(ContentModel.PROP_LINK_DESTINATION);
                  if (destRef != null && new Node(destRef).hasPermission(PermissionService.READ) == true)
                  {
                     node.addPropertyResolver("url", this.resolverLinkUrl);
                     node.addPropertyResolver("downloadUrl", this.resolverLinkDownload);
                     node.addPropertyResolver("webdavUrl", this.resolverLinkWebdavUrl);
                     node.addPropertyResolver("cifsPath", this.resolverLinkCifsPath);
                     node.addPropertyResolver("fileType16", this.resolverFileType16);
                     node.addPropertyResolver("fileType32", this.resolverFileType32);
                     node.addPropertyResolver("size", this.resolverSize);
                     node.addPropertyResolver("lang", this.resolverLang);

                     this.contentNodes.add(node);
                  }
               }
               else if (ApplicationModel.TYPE_FOLDERLINK.equals(type))
               {
                  // create our Folder Link Node representation
                  node = new MapNode(nodeRef, this.getNodeService(), fileInfo.getProperties());
                  // only display the user has the permissions to navigate to the target of the link
                        @SuppressWarnings("element-type-mismatch")
                  NodeRef destRef = (NodeRef)node.getProperties().get(ContentModel.PROP_LINK_DESTINATION);
                  if (destRef != null && new Node(destRef).hasPermission(PermissionService.READ) == true)
                  {
                     node.addPropertyResolver("icon", this.resolverSpaceIcon);
                     node.addPropertyResolver("smallIcon", this.resolverSmallIcon);

                     this.containerNodes.add(node);
                  }
               }

               // inform any listeners that a Node wrapper has been created
               if (node != null)
               {
                  for (NodeEventListener listener : nodeEventListeners)
                  {
                     listener.created(node, type);
                  }
               }
            }
            else
            {
               if (logger.isWarnEnabled())
                  logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
            }
         }

         // commit the transaction
         tx.commit();
      }
      catch (InvalidNodeRefException refErr)
      {
         Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
               FacesContext.getCurrentInstance(), Repository.ERROR_NODEREF), new Object[] {refErr.getNodeRef()}), refErr );
         this.containerNodes = Collections.<Node>emptyList();
         this.contentNodes = Collections.<Node>emptyList();
         try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
      }
      catch (Throwable err)
      {
         Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
               FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
         this.containerNodes = Collections.<Node>emptyList();
         this.contentNodes = Collections.<Node>emptyList();
         try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
      }

      if (logger.isDebugEnabled())
      {
         long endTime = System.currentTimeMillis();
         logger.debug("Time to query and build map nodes: " + (endTime - startTime) + "ms");
      }
   }

laurent1050
Champ in-the-making
Champ in-the-making
Thank you for your quick answer.

Unfortunately, that does not resolve my problem…

If you want more details on the problem, please see the following post http://forums.alfresco.com/en/viewtopic.php?f=12&t=28590&p=93322#p93322.

Laurent