/*
* (C) Copyright 2013-2014 Nuxeo SA (http://nuxeo.com/) and contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Contributors:
* Florent Guillaume
*/
package org.nuxeo.ecm.core.redis;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.text.StrBuilder;
import org.nuxeo.ecm.core.api.NuxeoException;
import org.nuxeo.runtime.RuntimeServiceEvent;
import org.nuxeo.runtime.RuntimeServiceListener;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.model.ComponentContext;
import org.nuxeo.runtime.model.ComponentInstance;
import org.nuxeo.runtime.model.DefaultComponent;
import org.nuxeo.runtime.model.SimpleContributionRegistry;
import org.osgi.framework.Bundle;
import redis.clients.jedis.Jedis;
/**
* Implementation of the Redis Service holding the configured Jedis pool.
*
* @since 5.8
*/
public class RedisComponent extends DefaultComponent implements RedisAdmin {
protected volatile RedisExecutor executor = RedisExecutor.NOOP;
protected RedisPoolDescriptor config;
protected SimpleContributionRegistry<RedisPoolDescriptor> registry =
new SimpleContributionRegistry<RedisPoolDescriptor>() {
@Override
public String getContributionId(RedisPoolDescriptor contrib) {
return "main";
}
@Override
public void contributionUpdated(String id, RedisPoolDescriptor contrib,
RedisPoolDescriptor newOrigContrib) {
config = contrib;
}
@Override
public void contributionRemoved(String id,
RedisPoolDescriptor origContrib) {
config = null;
}
};
protected String delsha;
@Override
public void registerContribution(Object contribution,
String extensionPoint, ComponentInstance contributor)
throws Exception {
if (contribution instanceof RedisPoolDescriptor) {
registry.addContribution((RedisPoolDescriptor) contribution);
} else {
super.registerContribution(contribution, extensionPoint,
contributor);
}
}
@Override
public void applicationStarted(ComponentContext context) throws Exception {
if (config == null || config.disabled) {
return;
}
Framework.addListener(new RuntimeServiceListener() {
@Override
public void handleEvent(RuntimeServiceEvent event) {
if (event.id != RuntimeServiceEvent.RUNTIME_ABOUT_TO_STOP) {
return;
}
Framework.removeListener(this);
executor = null;
executor.getPool().destroy();
}
});
handleNewExecutor(config.newExecutor());
}
public void handleNewExecutor(RedisExecutor executor) {
this.executor = executor;
try {
delsha = load("org.nuxeo.ecm.core.redis", "del-keys");
} catch (IOException cause) {
executor = null;
throw new NuxeoException("Cannot activate redis executor", cause);
}
}
@Override
public Long clear(final String pattern) throws IOException {
return executor.execute(new RedisCallable<Long>() {
@Override
public Long call(Jedis jedis) throws Exception {
List<String> keys = Arrays.asList(pattern);
List<String> args = Arrays.asList();
return (Long) jedis.evalsha(delsha, keys, args);
}
});
}
@Override
public String load(String bundleName, String scriptName) throws IOException {
Bundle b = Framework.getRuntime().getBundle(bundleName);
URL loc = b.getEntry(scriptName + ".lua");
InputStream is = loc.openStream();
final StrBuilder builder = new StrBuilder();
for (String line : IOUtils.readLines(is)) {
builder.appendln(line);
}
return executor.execute(new RedisCallable<String>() {
@Override
public String call(Jedis jedis) throws Exception {
return jedis.scriptLoad(builder.toString());
}
});
}
@Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter.isAssignableFrom(RedisExecutor.class)) {
return adapter.cast(executor);
}
return super.getAdapter(adapter);
}
@Override
public String namespace(String... names) {
StringBuilder builder = new StringBuilder("nuxeo:");
for (String name:names) {
builder.append(name).append(":");
}
return builder.toString();
}
}