/** * 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); }
private TransactionHelper getTransaction() { return importer.getTransaction(); }
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)); } }
/** * 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); } } } } }
/** {@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); } } } }