All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.bonita.identity.impl.PlainIdentityService Maven / Gradle / Ivy

/**
 * Copyright (C) 2007  Bull S. A. S.
 * Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation
 * version 2.1 of the License.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA  02110-1301, USA.
 **/
package org.ow2.bonita.identity.impl;

import java.io.EOFException;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Map.Entry;

import org.ow2.bonita.identity.GroupOp;
import org.ow2.bonita.identity.Membership;
import org.ow2.bonita.identity.UserOp;
import org.ow2.bonita.util.Base64;
import org.ow2.bonita.util.Misc;

/**
 * @author "Pierre Vigneras"
 * @date Nov 27, 2007
 */
public class PlainIdentityService extends PersistentIdentityService {

  public PlainIdentityService(final String fileName, boolean create) throws IOException {
    this(new File(fileName), create);
  }

  public PlainIdentityService(final File file, boolean create) throws IOException {
    super(file, create);
  }

  protected void flush() {
    PrintWriter pw = null;
    try {
      pw = new PrintWriter(file);
      pw.println(NEXT_HEADER + next);
      writeGroups(pw);
      writeUsers(pw);
      pw.flush();
    } catch (IOException ioe) {
      throw new RuntimeException(ioe);
    } finally {
      Misc.close(pw);
    }
  }

  private static final String NEXT_HEADER = "[Next]: ";

  private static final String USERS_NB_HEADER = "[Users nb]: ";

  private static final String USER_ID_HEADER = "[UserOp id]: ";

  private static final String USER_PROPERTIES_NB_HEADER = "[UserOp Properties nb]: ";

  private static final String USER_MEMBERSHIPS_NB_HEADER = "[UserOp Memberships nb]: ";

  private static final String USER_PERMISSIONS_HEADER = "[UserOp Permissions]: ";

  private static final String GROUP_NB_HEADER = "[Groups nb]: ";

  private static final String GROUP_ID_HEADER = "[GroupOp id]: ";

  private static final String GROUP_PARENT_HEADER = "[GroupOp parent]: ";

  private static final String GROUP_CHILDREN_NB_HEADER = "[GroupOp children]: ";

  private static final String GROUP_PROPERTIES_NB_HEADER = "[GroupOp Properties nb]: ";

  private static final String GROUP_MEMBERSHIPS_NB_HEADER = "[GroupOp Memberships nb]: ";

  private static final String GROUP_PERMISSIONS_HEADER = "[GroupOp Permissions]: ";

  private void writeGroups(final PrintWriter pw) throws IOException {
    pw.println(GROUP_NB_HEADER + groupOps.size());
    final Collection< ? extends GroupOp> groupCollection = groupOps.values();
    for (GroupOp groupOp : groupCollection) {
      pw.println(GROUP_ID_HEADER + groupOp.getId());
      pw.println(GROUP_PARENT_HEADER + groupOp.getParent().getId());
      final Set children = groupOp.getChildren();
      pw.println(GROUP_CHILDREN_NB_HEADER + children.size());
      StringBuilder sb = new StringBuilder();
      for (GroupOp child : children) {
        sb.append(child.getId() + " ");
      }
      if (sb.length() != 0) {
        pw.println(sb);
      }
      writeProperties(pw, groupOp.getProperties(), GROUP_PROPERTIES_NB_HEADER);
      final Set memberships = groupOp.getMemberships();
      pw.println(GROUP_MEMBERSHIPS_NB_HEADER + memberships.size());
      sb = new StringBuilder();
      for (Membership m : memberships) {
        sb.append(m.getUser().getId() + " ");
      }
      if (sb.length() != 0) {
        pw.println(sb);
      }
      writePermissions(pw, groupOp.getPermissions(), GROUP_PERMISSIONS_HEADER);
    }
  }

  private void writeProperties(final PrintWriter pw,
      final Properties properties, final String header) {
    final Set> props = properties.entrySet();
    pw.println(header + props.size());
    for (Entry p : props) {
      pw.println(p.getKey() + ": " + p.getValue());
    }
  }

  private void writePermissions(final PrintWriter pw,
      final Set permissions, final String header) throws IOException {
    //
    // final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // final ObjectOutputStream oos = new ObjectOutputStream(baos);
    // oos.writeObject(permissions);
    // oos.flush();
    // Don't use a string to transform bytes[] as some characters are translated
    // to '?'
    //final String base64Version = Base64.encodeObject((java.io.Serializable) permissions, Base64.DONT_BREAK_LINES | Base64.GZIP);
    String base64Version = Base64.encodeObject(
        (java.io.Serializable) permissions, Base64.DONT_BREAK_LINES
        | Base64.GZIP);
    if (base64Version == null) {
      throw new IOException("Error during base64 encoding of: " + permissions);
    }
    pw.println(header + base64Version);
  }

  private void writeUsers(final PrintWriter pw) throws IOException {
    pw.println(USERS_NB_HEADER + users.size());
    final Collection< ? extends UserOp> set = users.values();
    for (UserOp userOp : set) {
      pw.println(USER_ID_HEADER + userOp.getId());
      writeProperties(pw, userOp.getProperties(), USER_PROPERTIES_NB_HEADER);
      final Set memberships = userOp.getMemberships();
      pw.println(USER_MEMBERSHIPS_NB_HEADER + memberships.size());
      StringBuilder sb = new StringBuilder();
      for (Membership m : memberships) {
        sb.append(m.getGroup().getId() + " ");
      }
      if (sb.length() != 0) {
        pw.println(sb);
      }
      writePermissions(pw, userOp.getPermissions(), USER_PERMISSIONS_HEADER);
    }
  }

  protected void sync() {
    LineNumberReader reader = null;
    try {
      reader = new LineNumberReader(new FileReader(file));
      next = Integer.valueOf(readAfter(reader, NEXT_HEADER));
      final Map> groupMemberships = new HashMap>();
      groupOps = readGroups(reader, groupMemberships);
      final Map> userMemberships = new HashMap>();
      users = readUsers(reader, userMemberships);
      applyMemberships(userMemberships, groupMemberships);
    } catch (EOFException eofe) {
      init();
    } catch (LineNumberedIOException lne) {
      throw new RuntimeException(lne);
    } catch (Exception e) {
      throw new RuntimeException("Exception thrown at line: "
          + reader.getLineNumber(), e);
    }
  }

  private Map readGroups(LineNumberReader reader,
      Map> groupMemberships) throws IOException {
    final Map defined = new HashMap();
    defined.put(InMemoryIdentityService.ROOT_ID, GroupImpl.root());
    int groupNb = Integer.valueOf(readAfter(reader, GROUP_NB_HEADER));
    while (groupNb-- != 0) {
      // TODO: Depends on GroupImpl id: InMemoryIdentityService uses an Integer,
      // but it may be any object.
      final String id = readAfter(reader, GROUP_ID_HEADER);
      // Check if this group has already been referenced
      GroupImpl group = (GroupImpl) defined.get(id);
      if (group == null) {
        group = freshGroup();
        group.setId(id);
        defined.put(id, group);
      }
      final String parentId = readAfter(reader, GROUP_PARENT_HEADER);
      GroupImpl parent = (GroupImpl) defined.get(parentId);
      if (parent == null) {
        parent = freshGroup();
        parent.setId(parentId);
        defined.put(parentId, parent);
      }
      group.setParent(parent);
      int childrenNb = Integer.valueOf(readAfter(reader,
          GROUP_CHILDREN_NB_HEADER));
      final Set children = new HashSet();
      if (childrenNb != 0) {
        final String line = reader.readLine();
        final StringTokenizer tokenizer = new StringTokenizer(line);
        while (tokenizer.hasMoreTokens()) {
          final String childId = tokenizer.nextToken().trim();
          GroupImpl child = (GroupImpl) defined.get(childId);
          if (child == null) {
            child = freshGroup();
            child.setId(childId);
            defined.put(childId, child);
          }
          children.add(child);
        }
      }
      if (childrenNb != children.size()) {
        throw new LineNumberedIOException(reader,
            "Inconsistency detected: declared children nb is different from listed one!");
      }
      group.setChildren(children);
      int propertiesNb = Integer.valueOf(readAfter(reader,
          GROUP_PROPERTIES_NB_HEADER));
      final Properties properties = group.getProperties();
      readProperties(reader, propertiesNb, properties);
      group.setProperties(properties);
      int membershipNb = Integer.valueOf(readAfter(reader,
          GROUP_MEMBERSHIPS_NB_HEADER));
      final Set ids = readMembershipsIds(reader, membershipNb);
      groupMemberships.put(group, ids);
      final Set permissions = readPermissions(reader,
          GROUP_PERMISSIONS_HEADER);
      group.setPermissions(permissions);
    }
    // if (defined.size() != references.size()) throw new
    // IOException("Inconsistency detected: referenced groupOps and defined
    // groupOps are different!");
    return defined;
  }

  @SuppressWarnings("unchecked")
  private Set readPermissions(LineNumberReader reader, String header) throws IOException, Error {
    final String s = readAfter(reader, header).trim();
    // final byte[] bytes = Base64.decodeToObject(s);
    // Don't transform bytes into a String as some bytes are translated into '?'
    // final Permissions permissions = (Permissions) readFromBytes(bytes);
    //final Set permissions = (Set) Base64.decodeToObject(s);
    Set permissions = (Set) Base64.decodeToObject(s);
    if (permissions == null) {
      throw new IOException(
          "Error during the decoding of permissions from string: " + s);
    }
    return permissions;
  }

  private Properties readProperties(LineNumberReader reader, int propertiesNb,
      final Properties properties) throws IOException {
    while (propertiesNb-- != 0) {
      final String line = reader.readLine();
      final int i = line.indexOf(":");
      final String key = line.substring(0, i).trim();
      final String value = line.substring(i).trim();
      properties.setProperty(key, value);
    }
    return properties;
  }

  /*
  // Don't use String here since some bytes may be translated into '?'!!
  private Object readFromBytes(final byte[] bytes) throws IOException {
    final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    final ObjectInputStream ois = new ObjectInputStream(bais);
    Object object;
    try {
      object = ois.readObject();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
      throw new Error("Should never reach this statement!", e);
    }
    return object;
  }
  */

  private Map readUsers(final LineNumberReader reader,
      Map> userMemberships) throws IOException {
    final Map result = new HashMap();
    int userNb = Integer.valueOf(readAfter(reader, USERS_NB_HEADER));
    while (userNb-- != 0) {
      // TODO: Depends on UserImpl id: InMemoryIdentityService uses an Integer,
      // but it may be any object.
      final String id = readAfter(reader, USER_ID_HEADER);
      final UserImpl user = freshUser();
      user.setId(id);
      int propertiesNb = Integer.valueOf(readAfter(reader,
          USER_PROPERTIES_NB_HEADER));
      final Properties properties = user.getProperties();
      readProperties(reader, propertiesNb, properties);
      user.setProperties(properties);
      int membershipNb = Integer.valueOf(readAfter(reader,
          USER_MEMBERSHIPS_NB_HEADER));
      final Set ids = readMembershipsIds(reader, membershipNb);
      userMemberships.put(user, ids);
      final Set permissions = readPermissions(reader,
          USER_PERMISSIONS_HEADER);
      user.setPermissions(permissions);
      result.put(id, user);
    }
    return result;
  }

  /**
   * @param reader
   * @param membershipNb
   * @throws IOException
   */
  private Set readMembershipsIds(final LineNumberReader reader,
      int membershipNb) throws IOException {
    final Set ids = new HashSet();
    if (membershipNb == 0) {
      return ids;
    }
    final String line = reader.readLine();
    final StringTokenizer tokenizer = new StringTokenizer(line);
    while (tokenizer.hasMoreTokens()) {
      final String id = tokenizer.nextToken().trim();
      ids.add(id);
    }
    if (membershipNb != ids.size()) {
      throw new LineNumberedIOException(reader,
          "Inconsistency detected: declared memberships nb is different from listed one!");
    }
    return ids;
  }

  private String readAfter(final LineNumberReader reader, final String pattern) throws IOException {
    String s = reader.readLine();
    if (s == null) {
      throw new EOFException("End of file reached!");
    }
    s = s.trim();
    final int i = s.indexOf(pattern);
    if (i == -1) {
      throw new LineNumberedIOException(reader, "Can't find pattern " + pattern
          + " in string " + s);
    }
    return s.substring(i + pattern.length(), s.length()).trim();
  }

  private void applyMemberships(Map> userMemberships,
      Map> groupMemberships) throws IOException {
    final Collection ums = new ArrayList();
    for (UserImpl user : userMemberships.keySet()) {
      for (String groupId : userMemberships.get(user)) {
        final GroupImpl group = (GroupImpl) groupOps.get(groupId);
        if (group == null) {
          throw new IOException("Unknown GroupOp Id: " + groupId);
        }
        ums.add(new MembershipImpl(user, group));
      }
    }
    final Collection gms = new ArrayList();
    for (GroupImpl group : groupMemberships.keySet()) {
      for (String userId : groupMemberships.get(group)) {
        final UserImpl user = (UserImpl) users.get(userId);
        if (user == null) {
          throw new IOException("Unknown UserOp Id: " + userId);
        }
        gms.add(new MembershipImpl(user, group));
      }
    }
    for (MembershipImpl um : ums) {
      if (!gms.contains(um)) {
        throw new IOException("Inconsistency detected: user membership " + um
            + " is not specified in group memberships");
      }
      setMembership(um);
    }
  }

  private static class LineNumberedIOException extends IOException {
    /**
     * 
     */
    private static final long serialVersionUID = -7944755872653119683L;

    public LineNumberedIOException(LineNumberReader reader, String msg) {
      super(reader.getLineNumber() + ": " + msg);
    }

    public LineNumberedIOException(LineNumberReader reader, Throwable t) {
      super((t instanceof LineNumberedIOException) ? "" : (reader
          .getLineNumber() + ": "));
      initCause(t);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy