예제 #1
0
 /**
  * Begin re-import process for the given {@code books}.
  *
  * <p>Checks if we have permission first, and if we don't then will trigger a visual indication to
  * the user that we need the permission.
  *
  * @param books Books to re-import.
  */
 public static void reImportBooks(Iterable<RBook> books) {
   if (!Util.checkForStoragePermAndFireEventIfNeeded(R.id.action_execute_deferred)) {
     //noinspection unchecked    Defer this action while we ask for permission.
     setDeferredAction(params -> reImportBooks((Iterable<RBook>) params[0]), books);
     return;
   }
   Importer.get().queueReImport(books);
 }
예제 #2
0
 private TransactionHelper getTransaction() {
   return importer.getTransaction();
 }
예제 #3
0
public class Structure {

  private static final Logger log = LoggerFactory.getLogger(Structure.class);
  protected final String id;
  protected final String externalId;
  protected final Importer importer = Importer.getInstance();
  protected JsonObject struct;
  protected final Set<String> classes = Collections.synchronizedSet(new HashSet<String>());
  protected final Set<String> functionalGroups = Collections.synchronizedSet(new HashSet<String>());

  protected Structure(JsonObject struct) {
    this(struct.getString("externalId"), struct);
  }

  protected Structure(JsonObject struct, JsonArray groups, JsonArray classes) {
    this(struct);
    if (groups != null) {
      for (Object o : groups) {
        if (!(o instanceof String)) continue;
        functionalGroups.add((String) o);
      }
    }
    if (classes != null) {
      for (Object o : classes) {
        if (!(o instanceof String)) continue;
        this.classes.add((String) o);
      }
    }
  }

  protected Structure(String externalId, JsonObject struct) {
    if (struct != null && externalId != null && externalId.equals(struct.getString("externalId"))) {
      this.id = struct.getString("id");
    } else {
      throw new IllegalArgumentException("Invalid structure with externalId : " + externalId);
    }
    this.externalId = externalId;
    this.struct = struct;
  }

  private TransactionHelper getTransaction() {
    return importer.getTransaction();
  }

  public void update(JsonObject struct) {
    if (this.struct.equals(struct)) {
      return;
    }
    String query =
        "MATCH (s:Structure { externalId : {externalId}}) "
            + "WITH s "
            + "WHERE s.checksum IS NULL OR s.checksum <> {checksum} "
            + "SET "
            + Neo4j.nodeSetPropertiesFromJson("s", struct, "id", "externalId");
    getTransaction().add(query, struct);
    this.struct = struct;
  }

  public void create() {
    String query =
        "CREATE (s:Structure {props}) "
            + "WITH s "
            + "MATCH (p:Profile) "
            + "CREATE p<-[:HAS_PROFILE]-(g:Group:ProfileGroup {name : s.name+'-'+p.name})-[:DEPENDS]->s "
            + "SET g.id = id(g)+'-'+timestamp() ";
    JsonObject params =
        new JsonObject()
            .putString("id", id)
            .putString("externalId", externalId)
            .putObject("props", struct);
    getTransaction().add(query, params);
  }

  public synchronized Object[] addJointure(String externalId) {
    if (struct != null) {
      JsonArray joinKey = struct.getArray("joinKey");
      if (joinKey == null) {
        joinKey = new JsonArray();
        struct.putArray("joinKey", joinKey);
      }
      joinKey.add(externalId);
      String query =
          "MATCH (s:Structure {externalId: {externalId}}) " + "SET s.joinKey = {joinKey} ";
      JsonObject params =
          new JsonObject().putArray("joinKey", joinKey).putString("externalId", getExternalId());
      getTransaction().add(query, params);
      return joinKey.toArray();
    }
    return null;
  }

  public void addAttachment() {
    JsonArray functionalAttachment = struct.getArray("functionalAttachment");
    if (functionalAttachment != null
        && functionalAttachment.size() > 0
        && !externalId.equals(functionalAttachment.get(0))) {
      JsonObject params = new JsonObject().putString("externalId", externalId);
      String query;
      if (functionalAttachment.size() == 1) {
        query =
            "MATCH (s:Structure { externalId : {externalId}}), "
                + "(ps:Structure { externalId : {functionalAttachment}}) "
                + "CREATE UNIQUE s-[:HAS_ATTACHMENT]->ps";
        params.putString("functionalAttachment", (String) functionalAttachment.get(0));
      } else {
        query =
            "MATCH (s:Structure { externalId : {externalId}}), (ps:Structure) "
                + "WHERE ps.externalId IN {functionalAttachment} "
                + "CREATE UNIQUE s-[:HAS_ATTACHMENT]->ps";
        params.putArray("functionalAttachment", functionalAttachment);
      }
      getTransaction().add(query, params);
    }
  }

  public void createClassIfAbsent(String classExternalId, String name) {
    if (classes.add(classExternalId)) {
      String query =
          "MATCH (s:Structure { externalId : {structureExternalId}}) "
              + "CREATE s<-[:BELONGS]-(c:Class {props})"
              + "WITH s, c "
              + "MATCH s<-[:DEPENDS]-(g:ProfileGroup)-[:HAS_PROFILE]->(p:Profile) "
              + "CREATE c<-[:DEPENDS]-(pg:Group:ProfileGroup {name : c.name+'-'+p.name})-[:DEPENDS]->g "
              + "SET pg.id = id(pg)+'-'+timestamp() ";
      JsonObject params =
          new JsonObject()
              .putString("structureExternalId", externalId)
              .putObject(
                  "props",
                  new JsonObject()
                      .putString("externalId", classExternalId)
                      .putString("id", UUID.randomUUID().toString())
                      .putString("name", name));
      getTransaction().add(query, params);
    }
  }

  public void createFunctionalGroupIfAbsent(String groupExternalId, String name) {
    if (functionalGroups.add(groupExternalId)) {
      String query =
          "MATCH (s:Structure { externalId : {structureExternalId}}) "
              + "CREATE s<-[:DEPENDS]-(c:Group:FunctionalGroup {props}) ";
      JsonObject params =
          new JsonObject()
              .putString("structureExternalId", externalId)
              .putObject(
                  "props",
                  new JsonObject()
                      .putString("externalId", groupExternalId)
                      .putString("id", UUID.randomUUID().toString())
                      .putString("name", name));
      getTransaction().add(query, params);
    }
  }

  public void linkModules(String moduleExternalId) {
    String query =
        "MATCH (s:Structure { externalId : {externalId}}), "
            + "(m:Module { externalId : {moduleExternalId}}) "
            + "CREATE UNIQUE s-[:OFFERS]->m";
    JsonObject params =
        new JsonObject()
            .putString("externalId", externalId)
            .putString("moduleExternalId", moduleExternalId);
    getTransaction().add(query, params);
  }

  public void linkClassFieldOfStudy(String classExternalId, String fieldOfStudyExternalId) {
    String query =
        "MATCH (s:Structure { externalId : {externalId}})"
            + "<-[:BELONGS]-(c:Class { externalId : {classExternalId}}), "
            + "(f:FieldOfStudy { externalId : {fieldOfStudyExternalId}}) "
            + "CREATE UNIQUE c-[:TEACHES]->f";
    JsonObject params =
        new JsonObject()
            .putString("externalId", externalId)
            .putString("classExternalId", classExternalId)
            .putString("fieldOfStudyExternalId", fieldOfStudyExternalId);
    getTransaction().add(query, params);
  }

  public void linkGroupFieldOfStudy(String groupExternalId, String fieldOfStudyExternalId) {
    String query =
        "MATCH (s:Structure { externalId : {externalId}})"
            + "<-[:DEPENDS]-(c:FunctionalGroup { externalId : {groupExternalId}}), "
            + "(f:FieldOfStudy { externalId : {fieldOfStudyExternalId}}) "
            + "CREATE UNIQUE c-[:TEACHES]->f";
    JsonObject params =
        new JsonObject()
            .putString("externalId", externalId)
            .putString("groupExternalId", groupExternalId)
            .putString("fieldOfStudyExternalId", fieldOfStudyExternalId);
    getTransaction().add(query, params);
  }

  public String getExternalId() {
    return externalId;
  }

  public void transition(final Handler<Message<JsonObject>> handler) {
    final TransactionHelper tx = TransactionManager.getInstance().getTransaction("GraphDataUpdate");
    String query =
        "MATCH (s:Structure {id : {id}})<-[:BELONGS]-(c:Class)"
            + "<-[:DEPENDS]-(cpg:Group)<-[:IN]-(u:User) "
            + "OPTIONAL MATCH s<-[:DEPENDS]-(fg:FunctionalGroup) "
            + "RETURN collect(distinct u.id) as users, collect(distinct cpg.id) as profileGroups, "
            + "collect(distinct fg.id) as functionalGroups";
    JsonObject params = new JsonObject().putString("id", id);
    tx.getNeo4j()
        .execute(
            query,
            params,
            new Handler<Message<JsonObject>>() {
              @Override
              public void handle(Message<JsonObject> event) {
                JsonArray r = event.body().getArray("result");
                if ("ok".equals(event.body().getString("status")) && r != null && r.size() == 1) {
                  final JsonObject res = r.get(0);
                  usersInGroups(
                      new Handler<Message<JsonObject>>() {

                        @Override
                        public void handle(Message<JsonObject> event) {
                          for (Object u : res.getArray("users")) {
                            User.backupRelationship(u.toString(), tx);
                            User.transition(u.toString(), tx);
                          }
                          transitionClassGroup();
                          handler.handle(event);
                        }
                      });
                } else {
                  log.error("Structure " + id + " transition error.");
                  log.error(event.body().encode());
                  handler.handle(event);
                }
              }
            });
  }

  private void usersInGroups(Handler<Message<JsonObject>> handler) {
    final Neo4j neo4j = TransactionManager.getInstance().getNeo4j();
    final JsonObject params = new JsonObject().putString("id", id);
    String query =
        "MATCH (s:Structure {id : {id}})<-[:BELONGS]-(c:Class)"
            + "<-[:DEPENDS]-(cpg:Group) "
            + "OPTIONAL MATCH cpg<-[:IN]-(u:User) "
            + "RETURN cpg.id as group, cpg.name as groupName, collect(u.id) as users "
            + "UNION "
            + "MATCH (s:Structure {id : {id}})<-[r:DEPENDS]-(fg:FunctionalGroup) "
            + "OPTIONAL MATCH fg<-[:IN]-(u:User) "
            + "RETURN fg.id as group, fg.name as groupName, collect(u.id) as users ";
    neo4j.execute(query, params, handler);
  }

  private void transitionClassGroup() {
    TransactionHelper tx = TransactionManager.getInstance().getTransaction("GraphDataUpdate");
    JsonObject params = new JsonObject().putString("id", id);
    String query =
        "MATCH (s:Structure {id : {id}})<-[r:BELONGS]-(c:Class)"
            + "<-[r1:DEPENDS]-(cpg:Group)-[r2]-() "
            + "DELETE r, r1, r2, c, cpg ";
    tx.add(query, params);
    query =
        "MATCH (s:Structure {id : {id}})<-[r:DEPENDS]-(fg:FunctionalGroup) "
            + "OPTIONAL MATCH fg-[r1]-() "
            + "DELETE r, r1, fg";
    tx.add(query, params);
  }

  public static void count(TransactionHelper transactionHelper) {
    JsonObject params = new JsonObject();
    String query = "MATCH (s:Structure) RETURN count(distinct s) as nb";
    transactionHelper.add(query, params);
  }

  public static void list(
      JsonArray attributes, Integer skip, Integer limit, TransactionHelper transactionHelper) {
    StringBuilder query = new StringBuilder("MATCH (s:Structure) ");
    JsonObject params = new JsonObject();
    if (attributes != null && attributes.size() > 0) {
      query.append("RETURN DISTINCT");
      for (Object attribute : attributes) {
        query.append(" s.").append(attribute).append(" as ").append(attribute).append(",");
      }
      query.deleteCharAt(query.length() - 1);
      query.append(" ");
    } else {
      query.append("RETURN DISTINCT s ");
    }
    if (skip != null && limit != null) {
      query.append("ORDER BY externalId ASC " + "SKIP {skip} " + "LIMIT {limit} ");
      params.putNumber("skip", skip);
      params.putNumber("limit", limit);
    }
    transactionHelper.add(query.toString(), params);
  }

  public static void addAttachment(
      String structureId, String parentStructureId, TransactionHelper transactionHelper) {
    String query =
        "MATCH (s:Structure { id : {structureId}}), "
            + "(ps:Structure { id : {parentStructureId}}) "
            + "CREATE UNIQUE s-[r:HAS_ATTACHMENT]->ps "
            + "RETURN id(r) as id";
    transactionHelper.add(
        query,
        new JsonObject()
            .putString("structureId", structureId)
            .putString("parentStructureId", parentStructureId));
  }

  public static void removeAttachment(
      String structureId, String parentStructureId, TransactionHelper transactionHelper) {
    String query =
        "MATCH (s:Structure { id : {structureId}})-[r:HAS_ATTACHMENT]->(ps:Structure { id : {parentStructureId}}) "
            + "DELETE r";
    transactionHelper.add(
        query,
        new JsonObject()
            .putString("structureId", structureId)
            .putString("parentStructureId", parentStructureId));
  }
}
예제 #4
0
  /**
   * Rebuild index(es) in the backend instance. Note that the server will not explicitly initialize
   * this backend before calling this method.
   *
   * @param rebuildConfig The rebuild configuration.
   * @throws ConfigException If an unrecoverable problem arises during initialization.
   * @throws InitializationException If a problem occurs during initialization that is not related
   *     to the server configuration.
   * @throws DirectoryException If a Directory Server error occurs.
   */
  public void rebuildBackend(RebuildConfig rebuildConfig)
      throws InitializationException, ConfigException, DirectoryException {
    // If the backend already has the root container open, we must use the same
    // underlying root container
    boolean openRootContainer = rootContainer == null;

    /*
     * If the rootContainer is open, the backend is initialized by something
     * else. We can't do any rebuild of system indexes while others are using
     * this backend.
     */
    if (!openRootContainer && rebuildConfig.includesSystemIndex()) {
      Message message = ERR_JEB_REBUILD_BACKEND_ONLINE.get();
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    try {
      EnvironmentConfig envConfig;
      if (openRootContainer) {
        envConfig = new EnvironmentConfig();
        envConfig.setAllowCreate(true);
        envConfig.setTransactional(false);
        envConfig.setDurability(Durability.COMMIT_NO_SYNC);
        envConfig.setLockTimeout(0, TimeUnit.SECONDS);
        envConfig.setTxnTimeout(0, TimeUnit.SECONDS);
        envConfig.setConfigParam(
            EnvironmentConfig.CLEANER_MIN_FILE_UTILIZATION,
            String.valueOf(cfg.getDBCleanerMinUtilization()));
        envConfig.setConfigParam(
            EnvironmentConfig.LOG_FILE_MAX, String.valueOf(cfg.getDBLogFileMax()));

        Importer importer = new Importer(rebuildConfig, cfg, envConfig);
        rootContainer = initializeRootContainer(envConfig);
        importer.rebuildIndexes(rootContainer);
      } else {
        envConfig = ConfigurableEnvironment.parseConfigEntry(cfg);

        Importer importer = new Importer(rebuildConfig, cfg, envConfig);
        importer.rebuildIndexes(rootContainer);
      }
    } catch (ExecutionException execEx) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, execEx);
      }
      Message message = ERR_EXECUTION_ERROR.get(execEx.getMessage());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    } catch (InterruptedException intEx) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, intEx);
      }
      Message message = ERR_INTERRUPTED_ERROR.get(intEx.getMessage());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    } catch (ConfigException ce) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, ce);
      }
      throw new DirectoryException(
          DirectoryServer.getServerErrorResultCode(), ce.getMessageObject());
    } catch (JebException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw new DirectoryException(
          DirectoryServer.getServerErrorResultCode(), e.getMessageObject());
    } catch (InitializationException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw new InitializationException(e.getMessageObject());
    } finally {
      // If a root container was opened in this method as read only, close it
      // to leave the backend in the same state.
      if (openRootContainer && rootContainer != null) {
        try {
          rootContainer.close();
          rootContainer = null;
        } catch (DatabaseException e) {
          if (debugEnabled()) {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
        }
      }
    }
  }
예제 #5
0
  /** {@inheritDoc} */
  @Override()
  public LDIFImportResult importLDIF(LDIFImportConfig importConfig) throws DirectoryException {
    RuntimeInformation.logInfo();

    // If the backend already has the root container open, we must use the same
    // underlying root container
    boolean openRootContainer = rootContainer == null;

    // If the rootContainer is open, the backend is initialized by something
    // else.
    // We can't do import while the backend is online.
    if (!openRootContainer) {
      Message message = ERR_JEB_IMPORT_BACKEND_ONLINE.get();
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    try {
      EnvironmentConfig envConfig = new EnvironmentConfig();

      envConfig.setAllowCreate(true);
      envConfig.setTransactional(false);
      envConfig.setDurability(Durability.COMMIT_NO_SYNC);
      envConfig.setLockTimeout(0, TimeUnit.SECONDS);
      envConfig.setTxnTimeout(0, TimeUnit.SECONDS);
      envConfig.setConfigParam(
          EnvironmentConfig.CLEANER_MIN_FILE_UTILIZATION,
          String.valueOf(cfg.getDBCleanerMinUtilization()));
      envConfig.setConfigParam(
          EnvironmentConfig.LOG_FILE_MAX, String.valueOf(cfg.getDBLogFileMax()));

      if (!importConfig.appendToExistingData()) {
        if (importConfig.clearBackend() || cfg.getBaseDN().size() <= 1) {
          // We have the writer lock on the environment, now delete the
          // environment and re-open it. Only do this when we are
          // importing to all the base DNs in the backend or if the backend only
          // have one base DN.
          File parentDirectory = getFileForPath(cfg.getDBDirectory());
          File backendDirectory = new File(parentDirectory, cfg.getBackendId());
          // If the backend does not exist the import will create it.
          if (backendDirectory.exists()) {
            EnvManager.removeFiles(backendDirectory.getPath());
          }
        }
      }

      Importer importer = new Importer(importConfig, cfg, envConfig);
      rootContainer = initializeRootContainer(envConfig);
      return importer.processImport(rootContainer);
    } catch (ExecutionException execEx) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, execEx);
      }
      if (execEx.getCause() instanceof DirectoryException) {
        throw ((DirectoryException) execEx.getCause());
      } else {
        Message message = ERR_EXECUTION_ERROR.get(execEx.getMessage());
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
      }
    } catch (InterruptedException intEx) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, intEx);
      }
      Message message = ERR_INTERRUPTED_ERROR.get(intEx.getMessage());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    } catch (JebException je) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, je);
      }
      throw new DirectoryException(
          DirectoryServer.getServerErrorResultCode(), je.getMessageObject());
    } catch (InitializationException ie) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, ie);
      }
      throw new DirectoryException(
          DirectoryServer.getServerErrorResultCode(), ie.getMessageObject());
    } catch (ConfigException ce) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, ce);
      }
      throw new DirectoryException(
          DirectoryServer.getServerErrorResultCode(), ce.getMessageObject());
    } finally {
      // leave the backend in the same state.
      try {
        if (rootContainer != null) {
          long startTime = System.currentTimeMillis();
          rootContainer.close();
          long finishTime = System.currentTimeMillis();
          long closeTime = (finishTime - startTime) / 1000;
          Message msg = NOTE_JEB_IMPORT_LDIF_ROOTCONTAINER_CLOSE.get(closeTime);
          logError(msg);
          rootContainer = null;
        }

        // Sync the environment to disk.
        if (debugEnabled()) {
          Message message = NOTE_JEB_IMPORT_CLOSING_DATABASE.get();
          TRACER.debugInfo(message.toString());
        }
      } catch (DatabaseException de) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, de);
        }
      }
    }
  }