Search in sources :

Example 56 with ModifiableValueMap

use of org.apache.sling.api.resource.ModifiableValueMap in project sling by apache.

the class OakDiscoveryService method doUpdateProperties.

/**
     * Update the properties by inquiring the PropertyProvider's current values.
     * <p>
     * This method is invoked regularly by the heartbeatHandler.
     * The properties are stored in the repository under Config.getClusterInstancesPath()
     * and announced in the topology.
     * <p>
     * @see Config#getClusterInstancesPath()
     */
private void doUpdateProperties() {
    // SLING-5382 : the caller must ensure that this method
    // is not invoked after deactivation or before activation.
    // so this method doesn't have to do any further synchronization.
    // what we do nevertheless is a paranoia way of checking if
    // all variables are available and do a NOOP if that's not the case.
    final ResourceResolverFactory rrf = resourceResolverFactory;
    final Config c = config;
    final String sid = slingId;
    if (rrf == null || c == null || sid == null) {
        // cannot update the properties then..
        logger.debug("doUpdateProperties: too early to update the properties. " + "resourceResolverFactory ({}), config ({}) or slingId ({}) not yet set.", new Object[] { rrf, c, sid });
        return;
    } else {
        logger.debug("doUpdateProperties: updating properties now..");
    }
    final Map<String, String> newProps = new HashMap<String, String>();
    for (final ProviderInfo info : this.providerInfos) {
        info.refreshProperties();
        newProps.putAll(info.properties);
    }
    ResourceResolver resourceResolver = null;
    try {
        resourceResolver = rrf.getServiceResourceResolver(null);
        Resource myInstance = ResourceHelper.getOrCreateResource(resourceResolver, c.getClusterInstancesPath() + "/" + sid + "/properties");
        // SLING-2879 - revert/refresh resourceResolver here to work
        // around a potential issue with jackrabbit in a clustered environment
        resourceResolver.revert();
        resourceResolver.refresh();
        final ModifiableValueMap myInstanceMap = myInstance.adaptTo(ModifiableValueMap.class);
        final Set<String> keys = new HashSet<String>(myInstanceMap.keySet());
        for (final String key : keys) {
            if (newProps.containsKey(key)) {
                // perfect
                continue;
            } else if (key.indexOf(":") != -1) {
                // ignore
                continue;
            } else {
                // remove
                myInstanceMap.remove(key);
            }
        }
        boolean anyChanges = false;
        for (final Entry<String, String> entry : newProps.entrySet()) {
            Object existingValue = myInstanceMap.get(entry.getKey());
            if (entry.getValue().equals(existingValue)) {
                // SLING-3389: dont rewrite the properties if nothing changed!
                if (logger.isDebugEnabled()) {
                    logger.debug("doUpdateProperties: unchanged: {}={}", entry.getKey(), entry.getValue());
                }
                continue;
            }
            if (logger.isDebugEnabled()) {
                logger.debug("doUpdateProperties: changed: {}={}", entry.getKey(), entry.getValue());
            }
            anyChanges = true;
            myInstanceMap.put(entry.getKey(), entry.getValue());
        }
        if (anyChanges) {
            resourceResolver.commit();
        }
    } catch (LoginException e) {
        logger.error("handleEvent: could not log in administratively: " + e, e);
        throw new RuntimeException("Could not log in to repository (" + e + ")", e);
    } catch (PersistenceException e) {
        logger.error("handleEvent: got a PersistenceException: " + e, e);
        throw new RuntimeException("Exception while talking to repository (" + e + ")", e);
    } finally {
        if (resourceResolver != null) {
            resourceResolver.close();
        }
    }
    logger.debug("doUpdateProperties: updating properties done.");
}
Also used : HashMap(java.util.HashMap) Resource(org.apache.sling.api.resource.Resource) ModifiableValueMap(org.apache.sling.api.resource.ModifiableValueMap) ResourceResolverFactory(org.apache.sling.api.resource.ResourceResolverFactory) ResourceResolver(org.apache.sling.api.resource.ResourceResolver) PersistenceException(org.apache.sling.api.resource.PersistenceException) LoginException(org.apache.sling.api.resource.LoginException) HashSet(java.util.HashSet)

Example 57 with ModifiableValueMap

use of org.apache.sling.api.resource.ModifiableValueMap in project sling by apache.

the class OakClusterViewService method readOrDefineClusterId.

/**
     * oak's discovery-lite can opt to not provide a clusterViewId eg in the
     * single-VM case. (for clusters discovery-lite normally defines the
     * clusterViewId, as it is the one responsible for defining the membership
     * too) Thus if we're not getting an id here we have to define one here. (we
     * can typically assume that this corresponds to a singleVM case, but that's
     * not a 100% requirement). This id must be stored to ensure the contract
     * that the clusterId is stable across restarts. For that, the id is stored
     * under /var/discovery/oak (and to account for odd/edgy cases we'll do a
     * retry when storing the id, in case we'd run into conflicts, even though
     * they should not occur in singleVM cases)
     * 
     * @param resourceResolver the ResourceResolver with which to read or write
     * the clusterId properties under /var/discovery/oak
     * @return the clusterId to be used - either the one read or defined
     * at /var/discovery/oak - or the slingId in case of non-fixable exceptions
     * @throws PersistenceException when /var/discovery/oak could not be
     * accessed or auto-created
     */
private String readOrDefineClusterId(ResourceResolver resourceResolver) throws PersistenceException {
    //TODO: if Config gets a specific, public getDiscoveryResourcePath, this can be simplified:
    final String clusterInstancesPath = config.getClusterInstancesPath();
    final String discoveryResourcePath = clusterInstancesPath.substring(0, clusterInstancesPath.lastIndexOf("/", clusterInstancesPath.length() - 2));
    final int MAX_RETRIES = 5;
    for (int retryCnt = 0; retryCnt < MAX_RETRIES; retryCnt++) {
        Resource varDiscoveryOak = resourceResolver.getResource(discoveryResourcePath);
        if (varDiscoveryOak == null) {
            varDiscoveryOak = ResourceHelper.getOrCreateResource(resourceResolver, discoveryResourcePath);
        }
        if (varDiscoveryOak == null) {
            logger.error("readOrDefinedClusterId: Could not create: " + discoveryResourcePath);
            throw new RuntimeException("could not create " + discoveryResourcePath);
        }
        ModifiableValueMap props = varDiscoveryOak.adaptTo(ModifiableValueMap.class);
        if (props == null) {
            logger.error("readOrDefineClusterId: Could not adaptTo ModifiableValueMap: " + varDiscoveryOak);
            throw new RuntimeException("could not adaptTo ModifiableValueMap: " + varDiscoveryOak);
        }
        Object clusterIdObj = props.get(PROPERTY_CLUSTER_ID);
        String clusterId = (clusterIdObj == null) ? null : String.valueOf(clusterIdObj);
        if (clusterId != null && clusterId.length() > 0) {
            logger.trace("readOrDefineClusterId: read clusterId from repo as {}", clusterId);
            return clusterId;
        }
        // must now define a new clusterId and store it under /var/discovery/oak
        final String newClusterId = UUID.randomUUID().toString();
        props.put(PROPERTY_CLUSTER_ID, newClusterId);
        props.put(PROPERTY_CLUSTER_ID_DEFINED_BY, getSlingId());
        props.put(PROPERTY_CLUSTER_ID_DEFINED_AT, Calendar.getInstance());
        try {
            logger.info("readOrDefineClusterId: storing new clusterId as " + newClusterId);
            resourceResolver.commit();
            return newClusterId;
        } catch (PersistenceException e) {
            logger.warn("readOrDefineClusterId: could not persist clusterId " + "(retrying in 1 sec max " + (MAX_RETRIES - retryCnt - 1) + " more times: " + e, e);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                logger.warn("readOrDefineClusterId: got interrupted: " + e1, e1);
            }
            logger.info("readOrDefineClusterId: retrying now.");
        }
    }
    throw new RuntimeException("failed to write new clusterId (see log file earlier for more details)");
}
Also used : Resource(org.apache.sling.api.resource.Resource) PersistenceException(org.apache.sling.api.resource.PersistenceException) ModifiableValueMap(org.apache.sling.api.resource.ModifiableValueMap)

Example 58 with ModifiableValueMap

use of org.apache.sling.api.resource.ModifiableValueMap in project sling by apache.

the class OakViewChecker method resetLeaderElectionId.

/**
     * Hook that will cause a reset of the leaderElectionId
     * on next invocation of issueClusterLocalHeartbeat.
     * @return true if the leaderElectionId was reset - false if that was not
     * necessary as that happened earlier already and it has not propagated
     * yet to the ./clusterInstances in the meantime
     */
public boolean resetLeaderElectionId() {
    ResourceResolver resourceResolver = null;
    try {
        final String myClusterNodePath = getLocalClusterNodePath();
        resourceResolver = getResourceResolver();
        if (resourceResolver == null) {
            logger.warn("resetLeaderElectionId: could not login, new leaderElectionId will be calculated upon next heartbeat only!");
            return false;
        }
        String newLeaderElectionId = newLeaderElectionId();
        final Resource resource = ResourceHelper.getOrCreateResource(resourceResolver, myClusterNodePath);
        final ModifiableValueMap resourceMap = resource.adaptTo(ModifiableValueMap.class);
        resourceMap.put(PROPERTY_ID_RUNTIME, runtimeId);
        // SLING-4765 : store more infos to be able to be more verbose on duplicate slingId/ghost detection
        String slingHomePath = "n/a";
        if (slingSettingsService != null && slingSettingsService.getSlingHomePath() != null) {
            slingHomePath = slingSettingsService.getSlingHomePath();
        }
        resourceMap.put(PROPERTY_ID_SLING_HOME_PATH, slingHomePath);
        final String endpointsAsString = getEndpointsAsString();
        resourceMap.put(PROPERTY_ID_ENDPOINTS, endpointsAsString);
        Calendar leaderElectionCreatedAt = Calendar.getInstance();
        resourceMap.put("leaderElectionId", newLeaderElectionId);
        resourceMap.put("leaderElectionIdCreatedAt", leaderElectionCreatedAt);
        logger.info("resetLeaderElectionId: storing my runtimeId: {}, endpoints: {}, sling home path: {}, new leaderElectionId: {}, created at: {}", new Object[] { runtimeId, endpointsAsString, slingHomePath, newLeaderElectionId, leaderElectionCreatedAt });
        resourceResolver.commit();
    } catch (LoginException e) {
        logger.error("resetLeaderElectionid: could not login: " + e, e);
    } catch (PersistenceException e) {
        logger.error("resetLeaderElectionid: got PersistenceException: " + e, e);
    } finally {
        if (resourceResolver != null) {
            resourceResolver.close();
        }
    }
    return true;
}
Also used : Calendar(java.util.Calendar) ResourceResolver(org.apache.sling.api.resource.ResourceResolver) Resource(org.apache.sling.api.resource.Resource) PersistenceException(org.apache.sling.api.resource.PersistenceException) LoginException(org.apache.sling.api.resource.LoginException) ModifiableValueMap(org.apache.sling.api.resource.ModifiableValueMap)

Example 59 with ModifiableValueMap

use of org.apache.sling.api.resource.ModifiableValueMap in project sling by apache.

the class HeartbeatHandler method issueClusterLocalHeartbeat.

/** Issue a cluster local heartbeat (into the repository) **/
protected void issueClusterLocalHeartbeat() {
    if (logger.isDebugEnabled()) {
        logger.debug("issueClusterLocalHeartbeat: storing cluster-local heartbeat to repository for " + slingId);
    }
    ResourceResolver resourceResolver = null;
    final String myClusterNodePath = getLocalClusterNodePath();
    final Calendar currentTime = Calendar.getInstance();
    try {
        resourceResolver = getResourceResolver();
        if (resourceResolver == null) {
            logger.error("issueClusterLocalHeartbeat: no resourceresolver available!");
            return;
        }
        final Resource resource = ResourceHelper.getOrCreateResource(resourceResolver, myClusterNodePath);
        final ModifiableValueMap resourceMap = resource.adaptTo(ModifiableValueMap.class);
        if (firstHeartbeatWritten != -1 && lastHeartbeatWritten != null) {
            // SLING-2892: additional paranoia check
            // after the first heartbeat, check if there's someone else using
            // the same sling.id in this cluster
            final long timeSinceFirstHeartbeat = System.currentTimeMillis() - firstHeartbeatWritten;
            if (timeSinceFirstHeartbeat > 2 * config.getHeartbeatInterval()) {
                // but wait at least 2 heartbeat intervals to handle the situation
                // where a bundle is refreshed, and startup cases.
                final Calendar lastHeartbeat = resourceMap.get(PROPERTY_ID_LAST_HEARTBEAT, Calendar.class);
                if (lastHeartbeat != null) {
                    // the last time
                    if (!lastHeartbeatWritten.getTime().equals(lastHeartbeat.getTime())) {
                        // then we've likely hit the situation where there is another
                        // sling instance accessing the same repository (ie in the same cluster)
                        // using the same sling.id - hence writing to the same
                        // resource
                        invalidateCurrentEstablishedView();
                        discoveryServiceImpl.handleTopologyChanging();
                        logger.error("issueClusterLocalHeartbeat: SLING-2892: Detected unexpected, concurrent update of: " + myClusterNodePath + " 'lastHeartbeat'. If not done manually, " + "this likely indicates that there is more than 1 instance running in this cluster" + " with the same sling.id. My sling.id is " + slingId + "." + " Check for sling.id.file in your installation of all instances in this cluster " + "to verify this! Duplicate sling.ids are not allowed within a cluster!");
                    }
                }
            }
            // SLING-2901 : robust paranoia check: on first heartbeat write, the
            //              'runtimeId' is set as a property (ignoring any former value).
            //              If in subsequent calls the value of 'runtimeId' changes, then
            //              there is someone else around with the same slingId.
            final String readRuntimeId = resourceMap.get(PROPERTY_ID_RUNTIME, String.class);
            if (readRuntimeId == null) {
                // SLING-3977
                // someone deleted the resource property
                firstHeartbeatWritten = -1;
            } else if (!runtimeId.equals(readRuntimeId)) {
                invalidateCurrentEstablishedView();
                discoveryServiceImpl.handleTopologyChanging();
                final String slingHomePath = slingSettingsService == null ? "n/a" : slingSettingsService.getSlingHomePath();
                final String endpointsAsString = getEndpointsAsString();
                final String readEndpoints = resourceMap.get(PROPERTY_ID_ENDPOINTS, String.class);
                final String readSlingHomePath = resourceMap.get(PROPERTY_ID_SLING_HOME_PATH, String.class);
                logger.error("issueClusterLocalHeartbeat: SLING-2901: Detected more than 1 instance running in this cluster " + " with the same sling.id. " + "My sling.id: " + slingId + ", my runtimeId: " + runtimeId + ", my endpoints: " + endpointsAsString + ", my slingHomePath: " + slingHomePath + ", other runtimeId: " + readRuntimeId + ", other endpoints: " + readEndpoints + ", other slingHomePath:" + readSlingHomePath + " Check for sling.id.file in your installation of all instances in this cluster " + "to verify this! Duplicate sling.ids are not allowed within a cluster!");
                logger.error("issueClusterLocalHeartbeat: sending TOPOLOGY_CHANGING before self-disabling.");
                discoveryServiceImpl.forcedShutdown();
                logger.error("issueClusterLocalHeartbeat: disabling discovery.impl");
                activated = false;
                if (context != null) {
                    // disable all components
                    try {
                        context.getBundleContext().getBundle().stop();
                    } catch (BundleException e) {
                        logger.warn("issueClusterLocalHeartbeat: could not stop bundle: " + e, e);
                        // then disable all compnoents instead
                        context.disableComponent(null);
                    }
                }
                return;
            }
        }
        resourceMap.put(PROPERTY_ID_LAST_HEARTBEAT, currentTime);
        if (firstHeartbeatWritten == -1) {
            resourceMap.put(PROPERTY_ID_RUNTIME, runtimeId);
            // SLING-4765 : store more infos to be able to be more verbose on duplicate slingId/ghost detection
            final String slingHomePath = slingSettingsService == null ? "n/a" : slingSettingsService.getSlingHomePath();
            resourceMap.put(PROPERTY_ID_SLING_HOME_PATH, slingHomePath);
            final String endpointsAsString = getEndpointsAsString();
            resourceMap.put(PROPERTY_ID_ENDPOINTS, endpointsAsString);
            logger.info("issueClusterLocalHeartbeat: storing my runtimeId: {}, endpoints: {} and sling home path: {}", new Object[] { runtimeId, endpointsAsString, slingHomePath });
        }
        if (resetLeaderElectionId || !resourceMap.containsKey("leaderElectionId")) {
            // the new leaderElectionId might have been 'pre set' in the field 'newLeaderElectionId'
            // if that's the case, use that one, otherwise calculate a new one now
            final String newLeaderElectionId = this.newLeaderElectionId != null ? this.newLeaderElectionId : newLeaderElectionId(resourceResolver);
            this.newLeaderElectionId = null;
            resourceMap.put("leaderElectionId", newLeaderElectionId);
            resourceMap.put("leaderElectionIdCreatedAt", new Date());
            logger.info("issueClusterLocalHeartbeat: set leaderElectionId to " + newLeaderElectionId + " (resetLeaderElectionId: " + resetLeaderElectionId + ")");
            if (votingHandler != null) {
                votingHandler.setLeaderElectionId(newLeaderElectionId);
            }
            resetLeaderElectionId = false;
        }
        logger.debug("issueClusterLocalHeartbeat: committing cluster-local heartbeat to repository for {}", slingId);
        resourceResolver.commit();
        logger.debug("issueClusterLocalHeartbeat: committed cluster-local heartbeat to repository for {}", slingId);
        // SLING-2892: only in success case: remember the last heartbeat value written
        lastHeartbeatWritten = currentTime;
        // and set the first heartbeat written value - if it is not already set
        if (firstHeartbeatWritten == -1) {
            firstHeartbeatWritten = System.currentTimeMillis();
        }
    } catch (LoginException e) {
        logger.error("issueHeartbeat: could not log in administratively: " + e, e);
    } catch (PersistenceException e) {
        logger.error("issueHeartbeat: Got a PersistenceException: " + myClusterNodePath + " " + e, e);
    } finally {
        if (resourceResolver != null) {
            resourceResolver.close();
        }
    }
}
Also used : Calendar(java.util.Calendar) ResourceResolver(org.apache.sling.api.resource.ResourceResolver) Resource(org.apache.sling.api.resource.Resource) PersistenceException(org.apache.sling.api.resource.PersistenceException) LoginException(org.apache.sling.api.resource.LoginException) BundleException(org.osgi.framework.BundleException) ModifiableValueMap(org.apache.sling.api.resource.ModifiableValueMap) Date(java.util.Date)

Example 60 with ModifiableValueMap

use of org.apache.sling.api.resource.ModifiableValueMap in project sling by apache.

the class ResourceAccessSecurityImplTests method testCannotUpdateUsingReadableResourceIfCannotUpdate.

@Test
public void testCannotUpdateUsingReadableResourceIfCannotUpdate() {
    initMocks("/content", new String[] { "read", "update" });
    Resource resource = mock(Resource.class);
    when(resource.getPath()).thenReturn("/content");
    ModifiableValueMap valueMap = mock(ModifiableValueMap.class);
    when(resource.adaptTo(ModifiableValueMap.class)).thenReturn(valueMap);
    when(resourceAccessGate.canRead(resource)).thenReturn(ResourceAccessGate.GateResult.GRANTED);
    when(resourceAccessGate.canUpdate(resource)).thenReturn(ResourceAccessGate.GateResult.DENIED);
    Resource readableResource = resourceAccessSecurity.getReadableResource(resource);
    ModifiableValueMap resultValueMap = readableResource.adaptTo(ModifiableValueMap.class);
    assertNull(resultValueMap);
}
Also used : Resource(org.apache.sling.api.resource.Resource) ModifiableValueMap(org.apache.sling.api.resource.ModifiableValueMap) Test(org.junit.Test)

Aggregations

ModifiableValueMap (org.apache.sling.api.resource.ModifiableValueMap)111 Resource (org.apache.sling.api.resource.Resource)74 PersistenceException (org.apache.sling.api.resource.PersistenceException)32 Test (org.junit.Test)28 ResourceResolver (org.apache.sling.api.resource.ResourceResolver)26 HashMap (java.util.HashMap)22 ValueMap (org.apache.sling.api.resource.ValueMap)22 Calendar (java.util.Calendar)13 LoginException (org.apache.sling.api.resource.LoginException)9 ChildResource (org.apache.sling.validation.model.ChildResource)9 Date (java.util.Date)8 HashSet (java.util.HashSet)8 Map (java.util.Map)8 NonExistingResource (org.apache.sling.api.resource.NonExistingResource)8 ByteArrayInputStream (java.io.ByteArrayInputStream)7 IOException (java.io.IOException)7 ValidationModel (org.apache.sling.validation.model.ValidationModel)7 InputStream (java.io.InputStream)6 Node (javax.jcr.Node)6 RepositoryException (javax.jcr.RepositoryException)6