@Override public void notify(ChangeSet changeSet) { if (changeSet == null) { return; // do nothing } if (!isOpen.get()) { // The channel is not open ... return; } if (!multipleAddressesInCluster.get()) { // We are in clustered mode, but there is only one participant in the cluster (us). // So short-circuit the cluster and just notify the local observers ... if (hasObservers()) { delegate.notify(changeSet); logReceivedOperation(changeSet); } return; } // There are multiple participants in the cluster, so send all changes out to JGroups, // letting JGroups do the ordering of messages... try { logSendOperation(changeSet); byte[] data = serialize(changeSet); Message message = new Message(null, null, data); channel.send(message); } catch (IllegalStateException e) { LOGGER.warn( BusI18n.unableToNotifyChanges, clusteringConfiguration.getClusterName(), changeSet.size(), changeSet.getWorkspaceName(), changeSet.getUserId(), changeSet.getProcessKey(), changeSet.getTimestamp()); } catch (Exception e) { // Something went wrong here (this should not happen) ... String msg = BusI18n.errorSerializingChanges.text( clusteringConfiguration.getClusterName(), changeSet.size(), changeSet.getWorkspaceName(), changeSet.getUserId(), changeSet.getProcessKey(), changeSet.getTimestamp(), changeSet); throw new SystemFailureException(msg, e); } }
@Override public void notify(ChangeSet changeSet) { // do not store records from jcr:system boolean systemWorkspaceChanges = RepositoryConfiguration.SYSTEM_WORKSPACE_NAME.equalsIgnoreCase( changeSet.getWorkspaceName()); if (changeSet.isEmpty() || systemWorkspaceChanges) { return; } addRecords(new JournalRecord(changeSet)); }
protected final void logReceivedOperation(ChangeSet changeSet) { if (LOGGER.isTraceEnabled()) { LOGGER.trace( "Received on cluster '{0}' {1} changes on workspace {2} made by {3} from process '{4}' at {5}", clusteringConfiguration.getClusterName(), changeSet.size(), changeSet.getWorkspaceName(), changeSet.getUserId(), changeSet.getProcessKey(), changeSet.getTimestamp()); } }
protected ScanningTasks notify(ChangeSet changeSet) { if (changeSet.getWorkspaceName() == null) { // This is a change to the workspaces or repository metadata ... // Refresh the index definitions ... RepositoryIndexes indexes = readIndexDefinitions(); ScanningTasks feedback = new ScanningTasks(); if (!indexes.getIndexDefinitions().isEmpty()) { // Build up the names of the added and removed workspace names ... Set<String> addedWorkspaces = new HashSet<>(); Set<String> removedWorkspaces = new HashSet<>(); for (Change change : changeSet) { if (change instanceof WorkspaceAdded) { WorkspaceAdded added = (WorkspaceAdded) change; addedWorkspaces.add(added.getWorkspaceName()); } else if (change instanceof WorkspaceRemoved) { WorkspaceRemoved removed = (WorkspaceRemoved) change; removedWorkspaces.add(removed.getWorkspaceName()); } } if (!addedWorkspaces.isEmpty() || !removedWorkspaces.isEmpty()) { // Figure out which providers need to be called, and which definitions go with those // providers ... Map<String, List<IndexDefinition>> defnsByProvider = new HashMap<>(); for (IndexDefinition defn : indexes.getIndexDefinitions().values()) { String providerName = defn.getProviderName(); List<IndexDefinition> defns = defnsByProvider.get(providerName); if (defns == null) { defns = new ArrayList<>(); defnsByProvider.put(providerName, defns); } defns.add(defn); } // Then for each provider ... for (Map.Entry<String, List<IndexDefinition>> entry : defnsByProvider.entrySet()) { String providerName = entry.getKey(); WorkspaceIndexChanges changes = new WorkspaceIndexChanges(entry.getValue(), addedWorkspaces, removedWorkspaces); IndexProvider provider = providers.get(providerName); if (provider == null) continue; provider.notify( changes, repository.changeBus(), repository.nodeTypeManager(), repository.repositoryCache().getWorkspaceNames(), feedback.forProvider(providerName)); } } } return feedback; } if (!systemWorkspaceName.equals(changeSet.getWorkspaceName())) { // The change does not affect the 'system' workspace, so skip it ... return null; } // It is simple to listen to all local and remote changes. Therefore, any changes made locally // to the index definitions // will be propagated through the cached representation via this listener. AtomicReference<Map<Name, IndexChangeInfo>> changesByProviderName = new AtomicReference<>(); for (Change change : changeSet) { if (change instanceof NodeAdded) { NodeAdded added = (NodeAdded) change; Path addedPath = added.getPath(); if (indexesPath.isAncestorOf(addedPath)) { // Get the name of the affected provider ... Name providerName = addedPath.getSegment(2).getName(); if (addedPath.size() > 3) { // Adding an index (or column definition), but all we care about is the name of the // index Name indexName = addedPath.getSegment(3).getName(); changeInfoForProvider(changesByProviderName, providerName).changed(indexName); } } } else if (change instanceof NodeRemoved) { NodeRemoved removed = (NodeRemoved) change; Path removedPath = removed.getPath(); if (indexesPath.isAncestorOf(removedPath)) { // Get the name of the affected provider ... Name providerName = removedPath.getSegment(2).getName(); if (removedPath.size() > 4) { // It's a column definition being removed, so the index is changed ... Name indexName = removedPath.getSegment(3).getName(); changeInfoForProvider(changesByProviderName, providerName).removed(indexName); } else if (removedPath.size() > 3) { // Removing an index (or column definition), but all we care about is the name of the // index Name indexName = removedPath.getSegment(3).getName(); changeInfoForProvider(changesByProviderName, providerName).removed(indexName); } else if (removedPath.size() == 3) { // The whole provider was removed ... changeInfoForProvider(changesByProviderName, providerName).removedAll(); } } } else if (change instanceof PropertyChanged) { PropertyChanged propChanged = (PropertyChanged) change; Path changedPath = propChanged.getPathToNode(); if (indexesPath.isAncestorOf(changedPath)) { if (changedPath.size() > 3) { // Adding an index (or column definition), but all we care about is the name of the // index Name providerName = changedPath.getSegment(2).getName(); Name indexName = changedPath.getSegment(3).getName(); changeInfoForProvider(changesByProviderName, providerName).changed(indexName); } } } // we don't care about node moves (don't happen) or property added/removed (handled by node // add/remove) } if (changesByProviderName.get() == null || changesByProviderName.get().isEmpty()) { // No changes to the indexes ... return null; } // Refresh the index definitions ... RepositoryIndexes indexes = readIndexDefinitions(); // And notify the affected providers ... StringFactory strings = context.getValueFactories().getStringFactory(); ScanningTasks feedback = new ScanningTasks(); for (Map.Entry<Name, IndexChangeInfo> entry : changesByProviderName.get().entrySet()) { String providerName = strings.create(entry.getKey()); IndexProvider provider = providers.get(providerName); if (provider == null) continue; IndexChanges changes = new IndexChanges(); IndexChangeInfo info = entry.getValue(); if (info.removedAll) { // Get all of the definitions for this provider ... for (IndexDefinition defn : indexes.getIndexDefinitions().values()) { if (defn.getProviderName().equals(providerName)) changes.remove(defn.getName()); } } // Others might have been added or changed after the existing ones were removed ... for (Name name : info.removedIndexes) { changes.remove(strings.create(name)); } for (Name name : info.changedIndexes) { IndexDefinition defn = indexes.getIndexDefinitions().get(strings.create(name)); if (defn != null) changes.change(defn); } // Notify the provider ... try { provider.notify( changes, repository.changeBus(), repository.nodeTypeManager(), repository.repositoryCache().getWorkspaceNames(), feedback.forProvider(providerName)); } catch (RuntimeException e) { logger.error( e, JcrI18n.errorNotifyingProviderOfIndexChanges, providerName, repository.name(), e.getMessage()); } } // Finally swap the snapshot of indexes ... this.indexes = indexes; return feedback; }
@Override public void notify(ChangeSet changeSet) { if (!systemWorkspaceName.equals(changeSet.getWorkspaceName())) { // The change does not affect the 'system' workspace, so skip it ... return; } if (context.getProcessId().equals(changeSet.getProcessKey())) { // We generated these changes, so skip them ... return; } // Now process the changes ... Set<Name> nodeTypesToRefresh = new HashSet<Name>(); Set<Name> nodeTypesToDelete = new HashSet<Name>(); for (Change change : changeSet) { if (change instanceof NodeAdded) { NodeAdded added = (NodeAdded) change; Path addedPath = added.getPath(); if (nodeTypesPath.isAncestorOf(addedPath)) { // Get the name of the node type ... Name nodeTypeName = addedPath.getSegment(2).getName(); nodeTypesToRefresh.add(nodeTypeName); } } else if (change instanceof NodeRemoved) { NodeRemoved removed = (NodeRemoved) change; Path removedPath = removed.getPath(); if (nodeTypesPath.isAncestorOf(removedPath)) { // Get the name of the node type ... Name nodeTypeName = removedPath.getSegment(2).getName(); if (removedPath.size() == 3) { nodeTypesToDelete.add(nodeTypeName); } else { // It's a child defn or property defn ... if (!nodeTypesToDelete.contains(nodeTypeName)) { // The child defn or property defn is being removed but the node type is not ... nodeTypesToRefresh.add(nodeTypeName); } } } } else if (change instanceof PropertyChanged) { PropertyChanged propChanged = (PropertyChanged) change; Path changedPath = propChanged.getPathToNode(); if (nodeTypesPath.isAncestorOf(changedPath)) { // Get the name of the node type ... Name nodeTypeName = changedPath.getSegment(2).getName(); nodeTypesToRefresh.add(nodeTypeName); } } // we don't care about node moves (don't happen) or property added/removed (handled by node // add/remove) } if (nodeTypesToRefresh.isEmpty() && nodeTypesToDelete.isEmpty()) { // No changes return; } // There were at least some changes ... this.nodeTypesLock.writeLock().lock(); try { // Re-register the node types that were changed or added ... SessionCache systemCache = repository.createSystemSession(context, false); SystemContent system = new SystemContent(systemCache); Collection<NodeTypeDefinition> nodeTypes = system.readNodeTypes(nodeTypesToRefresh); registerNodeTypes(nodeTypes, false, false, false); // Unregister those that were removed ... unregisterNodeType(nodeTypesToDelete, false); } catch (Throwable e) { logger.error(e, JcrI18n.errorRefreshingNodeTypes, repository.name()); } finally { this.nodeTypesLock.writeLock().unlock(); } }