Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sling.discovery.commons.providers.spi.base;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.resource.observation.ResourceChange;
import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
import org.apache.sling.api.resource.observation.ResourceChangeListener;
import org.apache.sling.discovery.commons.providers.util.ResourceHelper;
import org.apache.sling.settings.SlingSettingsService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicyOption;
/**
* The IdMapService is responsible for storing a slingId-clusterNodeId
* pair to the repository and given all other instances in the cluster
* do the same can map clusterNodeIds to slingIds (or vice-versa)
*/
@Component(service = { IdMapService.class },
property = {
Constants.SERVICE_VENDOR + "=The Apache Software Foundation"
})
public class IdMapService extends AbstractServiceWithBackgroundCheck implements ResourceChangeListener {
@Reference(policyOption=ReferencePolicyOption.GREEDY)
private ResourceResolverFactory resourceResolverFactory;
@Reference(policyOption=ReferencePolicyOption.GREEDY)
private SlingSettingsService settingsService;
@Reference(policyOption=ReferencePolicyOption.GREEDY)
private DiscoveryLiteConfig commonsConfig;
private boolean initialized = false;
private String slingId;
private long me;
private final Map oldIdMapCache = new HashMap<>();
private final Map idMapCache = new HashMap<>();
private long lastCacheInvalidation = -1;
private BundleContext bundleContext;
private volatile ServiceRegistration eventHandlerRegistration;
/** test-only constructor **/
public static IdMapService testConstructor(
DiscoveryLiteConfig commonsConfig,
SlingSettingsService settingsService,
ResourceResolverFactory resourceResolverFactory) {
IdMapService service = new IdMapService();
service.commonsConfig = commonsConfig;
service.settingsService = settingsService;
service.resourceResolverFactory = resourceResolverFactory;
service.activate(null);
return service;
}
@Activate
protected void activate(BundleContext bundleContext) {
this.bundleContext = bundleContext;
registerEventHandler();
startBackgroundCheck("IdMapService-initializer", new BackgroundCheck() {
@Override
public boolean check() {
try {
return init();
} catch (Exception e) {
logger.error("initializer: could not init due to "+e, e);
return false;
}
}
}, null, -1, 1000 /* = 1sec interval */);
}
@Deactivate
protected void deactivate() {
if (eventHandlerRegistration != null) {
eventHandlerRegistration.unregister();
eventHandlerRegistration = null;
}
// SLING-5592: cancel the potentially running background thread
cancelPreviousBackgroundCheck();
}
private void registerEventHandler() {
if (bundleContext == null) {
logger.info("registerEventHandler: bundleContext is null - cannot register");
return;
}
Dictionary properties = new Hashtable<>();
properties.put(Constants.SERVICE_DESCRIPTION, "IdMap Change Listener.");
properties.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
String[] topics = new String[] {
ChangeType.ADDED.toString(),
ChangeType.CHANGED.toString(),
ChangeType.REMOVED.toString()
};
properties.put(ResourceChangeListener.CHANGES, topics);
properties.put(ResourceChangeListener.PATHS, getIdMapPath());
this.eventHandlerRegistration = bundleContext.registerService(ResourceChangeListener.class, this, properties);
}
/** Get or create a ResourceResolver **/
private ResourceResolver getResourceResolver() throws LoginException {
return resourceResolverFactory.getServiceResourceResolver(null);
}
public synchronized long getMyId() {
if (!initialized) {
return -1;
}
return me;
}
/** for testing only **/
public synchronized boolean waitForInit(long timeout) {
long start = System.currentTimeMillis();
while(!initialized && timeout != 0) {
try {
if (timeout>0) {
long diff = (start+timeout) - System.currentTimeMillis();
if (diff<=0) {
return false;
}
wait(diff);
} else {
wait();
}
} catch (InterruptedException e) {
// ignore
}
}
return initialized;
}
public synchronized boolean isInitialized() {
return initialized;
}
private synchronized boolean init() throws LoginException, PersistenceException {
if (initialized) {
return true;
}
slingId = settingsService.getSlingId();
ResourceResolver resourceResolver = null;
try{
resourceResolver = getResourceResolver();
DiscoveryLiteDescriptor descriptor =
DiscoveryLiteDescriptor.getDescriptorFrom(resourceResolver);
long me = descriptor.getMyId();
final Resource resource = ResourceHelper.getOrCreateResource(resourceResolver, getIdMapPath());
ModifiableValueMap idmap = resource.adaptTo(ModifiableValueMap.class);
// check to see if either my slingId is already mapped to another clusterNodeId
// or when my clusterNodeId is already mapped to another slingId
// in both cases: clean that up
boolean foundMe = false;
for (String aKey : new HashSet<>(idmap.keySet())) {
Object value = idmap.get(aKey);
if (value instanceof Number) {
Number n = (Number)value;
if (n.longValue()==me) {
// my clusterNodeId is already mapped to
// let's check if the key is my slingId
if (aKey.equals(slingId)) {
// perfect
foundMe = true;
} else {
// cleanup necessary
logger.info("init: my clusterNodeId is already mapped to by another slingId, deleting entry: key="+aKey+" mapped to "+value);
idmap.remove(aKey);
}
} else if (aKey.equals(slingId)) {
// cleanup necessary
logger.info("init: my slingId is already mapped to by another clusterNodeId, deleting entry: key="+aKey+" mapped to "+value);
idmap.remove(aKey);
} else {
// that's just some other slingId-clusterNodeId mapping
// leave it unchanged
}
}
}
if (!foundMe) {
logger.info("init: added the following mapping: slingId="+slingId+" to discovery-lite id="+me);
idmap.put(slingId, me);
} else {
logger.info("init: mapping already existed, left unchanged: slingId="+slingId+" to discovery-lite id="+me);
}
resourceResolver.commit();
this.me = me;
initialized = true;
notifyAll();
return true;
} catch(Exception e) {
logger.info("init: init failed: "+e);
return false;
} finally {
if (resourceResolver!=null) {
resourceResolver.close();
}
}
}
public synchronized void clearCache() {
if (!idMapCache.isEmpty()) {
logger.debug("clearCache: clearing idmap cache");
oldIdMapCache.clear();
oldIdMapCache.putAll(idMapCache);
idMapCache.clear();
} else {
logger.debug("clearCache: cache was already emtpy");
}
lastCacheInvalidation = System.currentTimeMillis();
}
public synchronized String toSlingId(int clusterNodeId, ResourceResolver resourceResolver) throws PersistenceException {
if (System.currentTimeMillis() - lastCacheInvalidation > 30000) {
// since upon a restart of an instance it could opt to have changed
// the slingId, we might not be able to catch that change if we
// noticed the view change before that (the view change would
// force a cache invalidation).
// we can either rely on observation - or combine that with
// an invalidation of once per minute
// (note that this means we'll be reading
// /var/discovery/oak/idMap once per minute - but that sounds
// perfectly fine)
clearCache();
}
String slingId = idMapCache.get(clusterNodeId);
if (slingId!=null) {
// cache-hit
return slingId;
}
// cache-miss
logger.debug("toSlingId: cache miss, refreshing idmap cache");
Map readMap = readIdMap(resourceResolver);
Set> newEntries = readMap.entrySet();
for (Entry newEntry : newEntries) {
String oldValue = oldIdMapCache.get(newEntry.getKey());
if (oldValue == null || !oldValue.equals(newEntry.getValue())) {
logger.info("toSlingId: mapping for "+newEntry.getKey()+" to "+newEntry.getValue() + " was newly added.");
} else if (!oldValue.equals(newEntry.getValue())) {
logger.info("toSlingId: mapping for "+newEntry.getKey()+" changed from "+oldValue+" to "+newEntry.getValue());
}
idMapCache.put(newEntry.getKey(), newEntry.getValue());
}
Set> oldEntries = oldIdMapCache.entrySet();
for (Entry oldEntry : oldEntries) {
if (!idMapCache.containsKey(oldEntry.getKey())) {
logger.info("toSlingId: mapping for "+oldEntry.getKey()+" to "+oldEntry.getValue()+" disappeared.");
}
}
return idMapCache.get(clusterNodeId);
}
private Map readIdMap(ResourceResolver resourceResolver) throws PersistenceException {
Resource resource = ResourceHelper.getOrCreateResource(resourceResolver, getIdMapPath());
ValueMap idmapValueMap = resource.adaptTo(ValueMap.class);
Map idmap = new HashMap<>();
for (String slingId : idmapValueMap.keySet()) {
Object value = idmapValueMap.get(slingId);
if (value instanceof Number) {
Number number = (Number)value;
idmap.put(number.intValue(), slingId);
}
}
return idmap;
}
private String getIdMapPath() {
return commonsConfig.getIdMapPath();
}
@Override
public void onChange(List changes) {
// the listener is registered on the .../idmap subpath, so any
// change it receives should be relevant. hence no further
// filtering necessary here.
logger.debug("onChange: got notified of changes, clearing cache.");
clearCache();
}
}