mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

matthew_swift
24.52.2009 5067760c866efc66b933457bd399affa47c9e9a4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.workflowelement;
 
 
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
 
import org.opends.server.admin.std.server.WorkflowElementCfg;
import org.opends.server.types.Operation;
import org.opends.server.types.CanceledOperationException;
 
 
/**
 * This class defines the super class for all the workflow elements. A workflow
 * element is a task in a workflow. A workflow element can wrap a physical
 * repository such as a local backend, a remote LDAP server or a local LDIF
 * file. A workflow element can also be used to route operations. This is the
 * case for load balancing and distribution. And workflow element can be used
 * in a virtual environment to transform data (DN and attribute renaming,
 * attribute value renaming...).
 *
 * @param  <T>  The type of configuration handled by this workflow element.
 */
public abstract class WorkflowElement <T extends WorkflowElementCfg>
    implements Observer
{
  // Indicates whether the workflow element encapsulates a private local
  // backend.
  private boolean isPrivate = false;
 
 
  // An information indicating the type of the current workflow element.
  // This information is for debug and tooling purpose only.
  private String workflowElementTypeInfo = "not defined";
 
 
  // The workflow element identifier.
  private String workflowElementID = null;
 
 
  // The observable state of the workflow element.
  private ObservableWorkflowElementState observableState =
    new ObservableWorkflowElementState(this);
 
 
  // The list of observers who want to be notified when a workflow element
  // required by the observer is created. The key of the map is a string
  // that identifies the newly created workflow element.
  private static ConcurrentMap<String, List<Observer>>
    newWorkflowElementNotificationList =
      new ConcurrentHashMap<String, List<Observer>>();
 
 
  // The observable status of the workflow element.
  // The status contains the health indicator (aka saturation index)
  // of the workflow element.
  private ObservableWorkflowElementStatus observableStatus =
    new ObservableWorkflowElementStatus(this);
 
 
  /**
   * Provides the observable state of the workflow element.
   * This method is intended to be called by the WorkflowElementConfigManager
   * that wants to notify observers that the workflow element state has
   * changed (in particular when a workflow element has been disabled).
   *
   * @return the observable state of the workflow element
   */
  protected ObservableWorkflowElementState getObservableState()
  {
    return observableState;
  }
 
 
  /**
   * Provides the observable status of the workflow element.
   *
   * @return the observable status of the workflow element.
   */
  protected ObservableWorkflowElementStatus getObservableStatus()
  {
    return observableStatus;
  }
 
 
  /**
   * Registers with a specific workflow element to be notified when the
   * workflow element state has changed. This notification system is
   * mainly used to be warned when a workflow element is enabled or
   * disabled.
   * <p>
   * If the workflow element <code>we</code> is not <code>null</code>
   * then the <code>observer</code> is registered with the list of objects
   * to notify when <code>we</code> has changed.
   * <p>
   * If the workflow element <code>we</code> is <code>null</code> then
   * the <code>observer</code> is registered with a static list of objects
   * to notify when a workflow element named <code>weid</code> is created.
   *
   * @param we        the workflow element. If <code>null</code> then observer
   *                  is registered with a list of workflow element
   *                  identifiers.
   * @param weid      the identifier of the workflow element. This parameter
   *                  is useless when <code>we</code> is not <code>null</code>
   * @param observer  the observer to notify when the workflow element state
   *                  has been modified
   */
  public static void registereForStateUpdate(
      WorkflowElement<?> we,
      String weid,
      Observer observer
      )
  {
    // If the workflow element "we" exists then register the observer with "we"
    // else register the observer with a static list of workflow element
    // identifiers
    if (we != null)
    {
      ObservableWorkflowElementState westate = we.getObservableState();
      westate.addObserver(observer);
    }
    else
    {
      if (weid == null)
      {
        return;
      }
 
      List<Observer> observers = newWorkflowElementNotificationList.get(weid);
      if (observers == null)
      {
        // create the list of observers
        observers = new CopyOnWriteArrayList<Observer>();
        observers.add(observer);
        newWorkflowElementNotificationList.put(weid, observers);
      }
      else
      {
        // update the observer list
        observers.add(observer);
      }
    }
  }
 
 
  /**
   * Deregisters an observer that was registered with a specific workflow
   * element.
   * <p>
   * If the workflow element <code>we</code> is not <code>null</code>
   * then the <code>observer</code> is deregistered with the list of objects
   * to notify when <code>we</code> has changed.
   * <p>
   * If the workflow element <code>we</code> is <code>null</code> then
   * the <code>observer</code> is deregistered with a static list of objects
   * to notify when a workflow element named <code>weid</code> is created.
   *
   * @param we        the workflow element. If <code>null</code> then observer
   *                  is deregistered with a list of workflow element
   *                  identifiers.
   * @param weid      the identifier of the workflow element. This parameter
   *                  is useless when <code>we</code> is not <code>null</code>
   * @param observer  the observer to deregister
   */
  public static void deregistereForStateUpdate(
      WorkflowElement<?> we,
      String weid,
      Observer observer
      )
  {
    // If the workflow element "we" exists then deregister the observer
    // with "we" else deregister the observer with a static list of
    // workflow element identifiers
    if (we != null)
    {
      ObservableWorkflowElementState westate = we.getObservableState();
      westate.deleteObserver(observer);
    }
 
    if (weid != null)
    {
      List<Observer> observers = newWorkflowElementNotificationList.get(weid);
      if (observers != null)
      {
        observers.remove(observer);
      }
    }
  }
 
 
  /**
   * Notifies all the observers who want to be warn when a workflow element
   * is created.
   *
   * @param workflowElement  the newly created workflow element
   */
  public static void notifyStateUpdate(
      WorkflowElement<?> workflowElement)
  {
    // Go through the list of observers and notify them all
    String weID = workflowElement.getWorkflowElementID();
 
    List<Observer> observers = newWorkflowElementNotificationList.get(weID);
    if (observers != null)
    {
      for (Observer observer: observers)
      {
        // The update might fail because an observer could have been
        // terminated. In this case, just ignore the failure and remove
        // the observer from the list of objects to notify.
        try
        {
          observer.update(workflowElement.getObservableState(), null);
        }
        catch(Exception e)
        {
          observers.remove(observer);
        }
      }
    }
  }
 
 
  /**
   * Creates a new instance of the workflow element.
   */
  public WorkflowElement()
  {
    // There is nothing to do in the constructor.
  }
 
 
  /**
   * Initializes the instance of the workflow element.
   *
   * @param workflowElementID  the workflow element identifier as defined
   *                           in the configuration.
   * @param workflowElementTypeInfo  an information to indicate the type of
   *                                 the current workflow element. For example
   *                                 "Backend" if the current workflow element
   *                                 is a local backend workflow element.
   */
  public void initialize(
      String workflowElementID,
      String workflowElementTypeInfo)
  {
    this.workflowElementID = workflowElementID;
    this.workflowElementTypeInfo = workflowElementTypeInfo;
  }
 
 
  /**
   * {@inheritDoc}
   */
  public void update(Observable o, Object arg)
  {
    // By default, do nothing when notification hits the workflow element.
  }
 
 
  /**
   * Get the type of the workflow element. The type is a string information
   * indicating which type is the current workflow element. This information
   * is intended to be used by tools for trace and debug purpose.
   *
   * @return the type of the workflow element.
   */
  public String getWorkflowElementTypeInfo()
  {
    return this.workflowElementTypeInfo;
  }
 
 
  /**
   * Indicates whether the provided configuration is acceptable for
   * this workflow element.
   *
   * @param  configuration        The workflow element configuration for
   *                              which to make the determination.
   * @param  unacceptableReasons  A list that may be used to hold the
   *                              reasons that the provided
   *                              configuration is not acceptable.
   *
   * @return  {@code true} if the provided configuration is acceptable
   *          for this workflow element, or {@code false} if not.
   */
  public boolean isConfigurationAcceptable(
      T configuration,
      List<String> unacceptableReasons)
  {
    // This default implementation does not perform any special
    // validation.  It should be overridden by workflow element
    // implementations that wish to perform more detailed validation.
    return true;
  }
 
 
  /**
   * Performs any finalization that might be required when this
   * workflow element is unloaded.  No action is taken in the default
   * implementation.
   */
  public void finalizeWorkflowElement()
  {
    // No action is required by default.
  }
 
  /**
   * Executes the workflow element for an operation.
   *
   * @param operation the operation to execute
   *
   * @throws CanceledOperationException if this operation should be
   * canceled
   */
  public abstract void execute(Operation operation)
      throws CanceledOperationException;
 
 
  /**
   * Indicates whether the workflow element encapsulates a private
   * local backend.
   *
   * @return <code>true</code> if the workflow element encapsulates a private
   *         local backend, <code>false</code> otherwise
   */
  public boolean isPrivate()
  {
    return isPrivate;
  }
 
 
  /**
   * Specifies whether the workflow element encapsulates a private local
   * backend.
   *
   * @param  isPrivate  Indicates whether the workflow element encapsulates a
   *                    private local backend.
   */
  protected void setPrivate(boolean isPrivate)
  {
    this.isPrivate = isPrivate;
  }
 
 
  /**
   * Provides the workflow element identifier.
   *
   * @return the workflow element identifier
   */
  public String getWorkflowElementID()
  {
    return workflowElementID;
  }
 
 
  /**
   * Modifies the saturation index of the workflow element.
   *
   * @param  newValue
   *         The new value of the saturation index of the workflow element.
   */
  public void setSaturationIndex(int newValue)
  {
    observableStatus.setSaturationIndex(newValue);
  }
 
 
  /**
   * Gets the saturation index of the workflow element.
   *
   * @return  the value of the saturation index of the workflow element.
   */
  public int getSaturationIndex()
  {
    return observableStatus.getSaturationIndex();
  }
 
 
  /**
   * Registers an observer with the saturation index of the workflow
   * element. The observer will be notified when the saturation index
   * is updated.
   *
   * @param  observer
   *         The observer to notify when the saturation index is modified.
   */
  public void registerForSaturationIndexUpdate(Observer observer)
  {
    observableStatus.addObserver(observer);
  }
 
 
  /**
   * Deregisters an observer with the saturation index of the workflow
   * element.
   *
   * @param  observer
   *         The observer to deregister.
   */
  public void deregisterForSaturationIndexUpdate(Observer observer)
  {
    observableStatus.deleteObserver(observer);
  }
 
  /**
   * Retrieves the list of child workflow elements, ie the
   * WorkflowElements below this one in the topology tree.
   *
   * @return child workflow elements
   */
  public abstract List<WorkflowElement<?>> getChildWorkflowElements();
 
  /**
   * Checks whether the tree of workflow elements below this one
   * contains the provided workflow element.
   *
   * @param element The WorkflowElement we are looking for in the topology
   *        below this object.
   * @return boolean
   */
  public boolean hasChildWorkflowElement(WorkflowElement element) {
    if (this.getChildWorkflowElements().size() == 0) {
      return (this.equals(element));
    }
 
    for (WorkflowElement subElement:this.getChildWorkflowElements()) {
      if (subElement.hasChildWorkflowElement(element)) {
        return true;
      }
    }
    return false;
  }
}