001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.core;
028    
029    
030    import org.opends.server.types.*;
031    
032    
033    /**
034     * This class implements the workflow node that handles the root DSE entry.
035     * As opposed to the WorkflowTopologyNode class, the root DSE node has no
036     * parent node nor subordinate nodes. Instead, the root DSE node has a set
037     * of naming contexts, each of which is a WorkflowTopologyNode object with
038     * no parent.
039     */
040    public class RootDseWorkflowTopology extends WorkflowTopology
041    {
042    
043      // The naming contexts known by the root DSE. These naming contexts
044      // are defined in the scope of a network group.
045      private NetworkGroupNamingContexts namingContexts = null;
046    
047    
048      /**
049       * Creates a workflow node to handle the root DSE entry.
050       *
051       * @param workflowImpl    the workflow which contains the processing for
052       *                        the root DSE backend
053       * @param namingContexts  the list of naming contexts being registered
054       *                        with the network group the root DSE belongs to
055       */
056      public RootDseWorkflowTopology(
057          WorkflowImpl               workflowImpl,
058          NetworkGroupNamingContexts namingContexts
059          )
060      {
061        super(workflowImpl);
062        this.namingContexts = namingContexts;
063      }
064    
065    
066      /**
067       * Executes an operation on the root DSE entry.
068       *
069       * @param operation the operation to execute
070       *
071       * @throws CanceledOperationException if this operation should
072       * be cancelled.
073       */
074      public void execute(Operation operation)
075          throws CanceledOperationException {
076        // Execute the operation.
077        OperationType operationType = operation.getOperationType();
078        if (operationType != OperationType.SEARCH)
079        {
080          // Execute the operation
081          getWorkflowImpl().execute(operation);
082        }
083        else
084        {
085          // Execute the SEARCH operation
086          executeSearch((SearchOperation) operation);
087        }
088      }
089    
090    
091      /**
092       * Executes a search operation on the the root DSE entry.
093       *
094       * @param searchOp the operation to execute
095       *
096       * @throws CanceledOperationException if this operation should
097       * be cancelled.
098       */
099      private void executeSearch(SearchOperation searchOp)
100          throws CanceledOperationException {
101        // Keep a the original search scope because we will alter it in the
102        // operation.
103        SearchScope originalScope = searchOp.getScope();
104    
105        // Search base?
106        // The root DSE entry itself is never returned unless the operation
107        // is a search base on the null suffix.
108        if (originalScope == SearchScope.BASE_OBJECT)
109        {
110          getWorkflowImpl().execute(searchOp);
111          return;
112        }
113    
114        // Create a workflow result code in case we need to perform search in
115        // subordinate workflows.
116        WorkflowResultCode workflowResultCode = new WorkflowResultCode(
117            searchOp.getResultCode(), searchOp.getErrorMessage());
118    
119        // The search scope is not 'base', so let's do a search on all the public
120        // naming contexts with appropriate new search scope and new base DN.
121        SearchScope newScope = elaborateScopeForSearchInSubordinates(originalScope);
122        searchOp.setScope(newScope);
123        DN originalBaseDN = searchOp.getBaseDN();
124    
125        for (WorkflowTopologyNode namingContext:
126             namingContexts.getPublicNamingContexts())
127        {
128          // We have to change the operation request base DN to match the
129          // subordinate workflow base DN. Otherwise the workflow will
130          // return a no such entry result code as the operation request
131          // base DN is a superior of the workflow base DN!
132          DN ncDN = namingContext.getBaseDN();
133    
134          // Set the new request base DN then do execute the operation
135          // in the naming context workflow.
136          searchOp.setBaseDN(ncDN);
137          namingContext.execute(searchOp);
138          boolean sendReferenceEntry =
139            workflowResultCode.elaborateGlobalResultCode(
140              searchOp.getResultCode(), searchOp.getErrorMessage());
141          if (sendReferenceEntry)
142          {
143            // TODO jdemendi - turn a referral result code into a reference entry
144            // and send the reference entry to the client application
145          }
146        }
147    
148        // Now restore the original request base DN and original search scope
149        searchOp.setBaseDN(originalBaseDN);
150        searchOp.setScope(originalScope);
151    
152        // Set the operation result code and error message
153        searchOp.setResultCode(workflowResultCode.resultCode());
154        searchOp.setErrorMessage(workflowResultCode.errorMessage());
155      }
156    
157    
158      /**
159       * Dumps info from the current workflow for debug purpose.
160       *
161       * @param leftMargin  white spaces used to indent the traces
162       * @return a string buffer that contains trace information
163       */
164      public StringBuilder toString(String leftMargin)
165      {
166        StringBuilder sb = new StringBuilder();
167    
168        // display the identifier and baseDN
169        String workflowID = this.getWorkflowImpl().getWorkflowId();
170        sb.append(leftMargin + "Workflow ID = " + workflowID + "\n");
171        sb.append(leftMargin + "         baseDN:[ \"\" ]\n");
172    
173        return sb;
174      }
175    
176    }