
io.joynr.channel.ChannelUrlDirectoyImpl Maven / Gradle / Ivy
The newest version!
package io.joynr.channel;
/*
* #%L
* %%
* Copyright (C) 2011 - 2014 BMW Car IT GmbH
* %%
* Licensed 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.
* #L%
*/
import io.joynr.provider.DeferredVoid;
import io.joynr.provider.Promise;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import joynr.infrastructure.ChannelUrlDirectoryAbstractProvider;
import joynr.types.ChannelUrlInformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
/**
* The channelurldirectory stores channelIds mapped to channelUrls.
*
*
* channelurls are stored in a concurrentHashMap. Using a in memory database could be possible optimization.
*/
// TODO Evaluate pro /cons of a in memory database
@Singleton
public class ChannelUrlDirectoyImpl extends ChannelUrlDirectoryAbstractProvider {
private static final Logger logger = LoggerFactory.getLogger(ChannelUrlDirectoyImpl.class);
public static final String CHANNELURL_INACTIVE_TIME_IN_MS = "joynr.channel.channelurlinactivetime";
final long channelurInactiveTimeInMS;
private ConcurrentHashMap registeredChannels = new ConcurrentHashMap();
Map inactiveChannelIds = new ConcurrentHashMap();
private Thread cleanupThread;
private Map> pendingDeferredsMap;
public ConcurrentHashMap getRegisteredChannels() {
return registeredChannels;
}
@Inject
public ChannelUrlDirectoyImpl(@Named(CHANNELURL_INACTIVE_TIME_IN_MS) long inactiveTimeInMS) {
channelurInactiveTimeInMS = inactiveTimeInMS;
pendingDeferredsMap = Maps.newConcurrentMap();
cleanupThread = new Thread(new Runnable() {
@Override
public void run() {
cleanupRunnable();
}
});
cleanupThread.start();
}
private void cleanupRunnable() {
while (true) {
synchronized (cleanupThread) {
if (inactiveChannelIds.size() == 0) {
try {
cleanupThread.wait();
} catch (InterruptedException e) {
}
} else {
long currentTime = System.currentTimeMillis();
long timeToSleep = -1;
for (Entry inactiveChannelId : inactiveChannelIds.entrySet()) {
String channelId = inactiveChannelId.getKey();
long passedTime = currentTime - inactiveChannelId.getValue();
if (passedTime >= channelurInactiveTimeInMS) {
logger.debug("GLOBAL unregisterChannelUrls channelId: {}", channelId);
registeredChannels.remove(channelId);
inactiveChannelIds.remove(channelId);
} else {
if (timeToSleep == -1 || timeToSleep > channelurInactiveTimeInMS - passedTime) {
timeToSleep = channelurInactiveTimeInMS - passedTime;
}
}
}
if (timeToSleep != -1) {
try {
cleanupThread.wait(timeToSleep);
} catch (InterruptedException e) {
}
}
}
}
}
}
@Override
public Promise getUrlsForChannel(String channelId) {
GetUrlsForChannelDeferred deferred = new GetUrlsForChannelDeferred();
ChannelUrlInformation channelUrlInformation = registeredChannels.get(channelId);
if (channelUrlInformation == null) {
addPendingCallback(deferred, channelId);
logger.warn("GLOBAL getUrlsForChannel for Channel: {} found nothing. Invoke callbacks once ChannelUrlInformation becomes available",
channelId);
} else {
logger.debug("GLOBAL getUrlsForChannel ChannelUrls for channelId {} found: {}",
channelId,
channelUrlInformation);
deferred.resolve(channelUrlInformation);
}
return new Promise(deferred);
}
private synchronized void addPendingCallback(GetUrlsForChannelDeferred deferred, String channelId) {
if (pendingDeferredsMap.get(channelId) == null) {
pendingDeferredsMap.put(channelId, Lists. newArrayList());
}
pendingDeferredsMap.get(channelId).add(deferred);
// TODO drop the newly added callback from the pendingCallbackMap after a while, avoiding a continuously growing
// map
}
@Override
public Promise registerChannelUrls(String channelId, ChannelUrlInformation channelUrlInformation) {
logger.debug("GLOBAL registerChannelUrls channelId: {} channelUrls: {}", channelId, channelUrlInformation);
DeferredVoid deferred = new DeferredVoid();
registeredChannels.put(channelId, channelUrlInformation);
inactiveChannelIds.remove(channelId);
if (deferred != null) {
deferred.resolve();
}
List pendingDeferreds = pendingDeferredsMap.remove(channelId);
if (pendingDeferreds != null) {
for (GetUrlsForChannelDeferred pendingDeferred : pendingDeferreds) {
pendingDeferred.resolve(channelUrlInformation);
}
}
return new Promise(deferred);
}
@Override
public Promise unregisterChannelUrls(String channelId) {
DeferredVoid deferred = new DeferredVoid();
inactiveChannelIds.put(channelId, System.currentTimeMillis());
synchronized (cleanupThread) {
cleanupThread.notify();
}
deferred.resolve();
return new Promise(deferred);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy