<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 11/09/2012 07:57 AM, Boleslaw
      Dawidowicz wrote:<br>
    </div>
    <blockquote
      cite="mid:85B41740-5111-442A-B2DF-14E8610039EE@redhat.com"
      type="cite">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div>On Nov 6, 2012, at 11:10 PM, Shane Bryzak &lt;<a
          moz-do-not-send="true" href="mailto:sbryzak@redhat.com">sbryzak@redhat.com</a>&gt;
        wrote:<br>
        <br>
      </div>
      <blockquote type="cite">
        <div>
          <meta content="text/html; charset=UTF-8"
            http-equiv="Content-Type">
          <div class="moz-cite-prefix">On 11/07/2012 07:35 AM, Boleslaw
            Dawidowicz wrote:<br>
          </div>
          <blockquote
            cite="mid:5F7EEC45-6F54-4C08-8318-D5BE0502ADB2@redhat.com"
            type="cite">
            <meta http-equiv="content-type" content="text/html;
              charset=UTF-8">
            <div>Also +1. It looks really good.</div>
            <div><br>
            </div>
            <div>I assume the strategy to handle operations when two
              stores are configured is IdentityManager implementation
              area. I wonder if we should make this part also more
              flexible in some way. Not really thinking about
              IdentityStoreRepository kind of design I had in 1.x as it
              is probably a bit too much. However it should be at least
              easy to extend DefaultIdentityManager to add some
              customizations to how specific operations are handled. Or
              we should have something like GenericIdentityManager for
              such purpose.</div>
          </blockquote>
          <br>
          This feature (which I've been referring to as partitioning) is
          supported by requiring each configured IdentityStore to
          provide metadata as to which features are supported, via the
          getFeatureSet() method:<br>
          <br>
          Set&lt;Feature&gt; getFeatureSet();<br>
          <br>
          Feature is an enum defining all currently supported identity
          management operations:<br>
          <br>
              public enum Feature { createUser, readUser, updateUser,
          deleteUser, <br>
                                    createGroup, readGroup, updateGroup,
          deleteGroup,<br>
                                    createRole, readRole, updateRole,
          deleteRole,<br>
                                    createMembership, readMembership,
          updateMembership, deleteMembership,<br>
                                    validateCredential,
          updateCredential,<br>
                                    all }<br>
          <br>
          When an IdentityManager method is invoked, the correct
          IdentityStore for the required operation is selected based on
          its supported feature set.  Here's an example of this, in the
          createUser() method:<br>
          <br>
          <br>
              @Override<br>
              public User createUser(String name) {<br>
                  User user = new SimpleUser(name);<br>
                  IdentityStore store =
          getStoreForFeature(Feature.createUser); <br>
                 
          store.createUser(getContextFactory().getContext(store), user);<br>
                  return user;<br>
              }<br>
          <br>
          The getStoreForFeature() method iterates through the
          configured stores and returns the one that supports the
          specified Feature, in this example Feature.createUser.  This
          way we can configure multiple stores with one of them
          providing user-related operations, one providing group and
          role operations, and so forth.<br>
          <br>
        </div>
      </blockquote>
      <div><br>
      </div>
      <div>This will still not cover all use cases.</div>
      <div><br>
      </div>
      <div>You have few stores that support credential validation and
        implement some kind of strategy like in pam. I'm not saying that
        spi should be more complex - no I think it is rather perfect for
        the balance between complexity and features. Just pointing out
        that people will need to extend IdentityManager to introduce
        some more complex multi store behaviors. Implementation should
        be done with it in mind. Avoid private methods and so on.</div>
    </blockquote>
    <br>
    It should be relatively simple to extend the default IdentityManager
    and override this behaviour if the developer wants something else.<br>
    <br>
    <blockquote
      cite="mid:85B41740-5111-442A-B2DF-14E8610039EE@redhat.com"
      type="cite"><br>
      <blockquote type="cite">
        <div>
          <blockquote
            cite="mid:5F7EEC45-6F54-4C08-8318-D5BE0502ADB2@redhat.com"
            type="cite">
            <div><br>
            </div>
            <div>Looking forward to see your ideas around design of
              event handling part. I think it will be critical to truly
              pluggable and extendable.<br>
            </div>
          </blockquote>
          <br>
          This feature was quite simple.  I've opted to go with the
          "class as an event" model, where each event type is
          represented by a POJO containing the relevant event state. 
          For example, the following event is raised when a new user is
          created:<br>
          <br>
          public class UserCreatedEvent extends AbstractBaseEvent {<br>
              private User user;<br>
          <br>
              public UserCreatedEvent(User user) {<br>
                  this.user = user;<br>
              }<br>
          <br>
              public User getUser() {<br>
                  return user;<br>
              }<br>
          }<br>
          <br>
          In this example, the event class contains a reference to the
          User that was created.  In addition to this, each event class
          should extend AbstractBaseEvent which also provides an event
          context:<br>
          <br>
          public abstract class AbstractBaseEvent {<br>
              private EventContext context = new EventContext();<br>
          <br>
              public EventContext getContext() {<br>
                  return context;<br>
              }<br>
          }<br>
          <br>
          The EventContext provides a general purpose mechanism for
          passing arbitrary state:<br>
          <br>
          public class EventContext {<br>
              private Map&lt;String,Object&gt; context;<br>
          <br>
              public Object getValue(String name) {<br>
                  return context != null ? context.get(name) : null;<br>
              }<br>
          <br>
              public void setValue(String name, Object value) {<br>
                  if (context == null) {<br>
                      context = new HashMap&lt;String,Object&gt;();<br>
                  }<br>
                  context.put(name, value);<br>
              }<br>
          <br>
              public boolean contains(String name) {<br>
                  return context != null &amp;&amp;
          context.containsKey(name);<br>
              }<br>
          <br>
              public boolean isEmpty() {<br>
                  return context == null || context.isEmpty();<br>
              }<br>
          }<br>
          <br>
          It is via the EventContext that we can pass IdentityStore
          implementation-specific state (for example the actual entity
          bean instance that was persisted to the database in the case
          of a JPA backed IdentityStore) or any additional state that
          might be relevant to the event.<br>
          <br>
          As for bridging the event itself, the
          IdentityStoreInvocationContext provides access to the
          EventBridge via the getEventBridge() method:<br>
          <br>
          EventBridge getEventBridge();<br>
          <br>
          This is an extremely simple interface declaring just a single
          method:<br>
          <br>
          public interface EventBridge {<br>
              void raiseEvent(Object event);<br>
          }<br>
          <br>
          The idea here is that you can provide an EventBridge
          implementation tailored for the environment that you're
          running in.  In an EE6 environment, this is a piece of cake as
          we just pass the event straight on through to the CDI event
          bus.<br>
          <br>
          That pretty much sums up event handling.<br>
        </div>
      </blockquote>
      <div><br>
      </div>
      <div>Looks pretty simple indeed. What I had in mind was something
        with post and per operation events but I guess that if needed
        those would fit this design right? It more seems about defining
        valid event types and raising points.</div>
      <div><br>
      </div>
      <div>I would like to be able to have access to full context - not
        just the single store. Use case is for example to synchronize or
        propagate objects from one identity store into other one in case
        of specific operation.</div>
    </blockquote>
    <br>
    Pre and post operation events will fit this design easily, yes. 
    Propagation should be possible by creating a 'wrapper' IdentityStore
    that synchronizes identity state from one of the wrapped stores into
    another (I wouldn't base this on the event API).  I'm not quite
    convinced that synchronization is such a useful thing though, could
    you enlighten me with a use case where this would be required?<br>
    <br>
    <br>
    <br>
  </body>
</html>