001/* 002 * (C) Copyright 2013-2017 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.core.redis; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.net.URL; 024import java.util.Collections; 025 026import org.apache.commons.io.IOUtils; 027import org.apache.commons.lang.StringUtils; 028import org.apache.commons.lang.text.StrBuilder; 029import org.nuxeo.ecm.core.api.NuxeoException; 030import org.nuxeo.runtime.api.Framework; 031import org.nuxeo.runtime.model.ComponentContext; 032import org.nuxeo.runtime.model.ComponentInstance; 033import org.nuxeo.runtime.model.DefaultComponent; 034import org.nuxeo.runtime.model.SimpleContributionRegistry; 035import org.osgi.framework.Bundle; 036 037/** 038 * Implementation of the Redis Service holding the configured Jedis pool. 039 * 040 * @since 5.8 041 */ 042public class RedisComponent extends DefaultComponent implements RedisAdmin { 043 044 private static final String DEFAULT_PREFIX = "nuxeo:"; 045 046 protected volatile RedisExecutor executor; 047 048 protected RedisPoolDescriptorRegistry registry = new RedisPoolDescriptorRegistry(); 049 050 public static class RedisPoolDescriptorRegistry extends SimpleContributionRegistry<RedisPoolDescriptor> { 051 052 protected RedisPoolDescriptor config; 053 054 @Override 055 public String getContributionId(RedisPoolDescriptor contrib) { 056 return "main"; 057 } 058 059 @Override 060 public void contributionUpdated(String id, RedisPoolDescriptor contrib, RedisPoolDescriptor newOrigContrib) { 061 config = contrib; 062 } 063 064 @Override 065 public void contributionRemoved(String id, RedisPoolDescriptor origContrib) { 066 config = null; 067 } 068 069 public RedisPoolDescriptor getConfig() { 070 return config; 071 } 072 073 public void clear() { 074 config = null; 075 } 076 } 077 078 protected String delsha; 079 080 @Override 081 public void activate(ComponentContext context) { 082 super.activate(context); 083 registry.clear(); 084 } 085 086 @Override 087 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 088 if (contribution instanceof RedisPoolDescriptor) { 089 registerRedisPoolDescriptor((RedisPoolDescriptor) contribution); 090 } else { 091 throw new NuxeoException("Unknown contribution class: " + contribution); 092 } 093 } 094 095 @Override 096 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 097 if (contribution instanceof RedisPoolDescriptor) { 098 unregisterRedisPoolDescriptor((RedisPoolDescriptor) contribution); 099 } 100 } 101 102 public void registerRedisPoolDescriptor(RedisPoolDescriptor contrib) { 103 registry.addContribution(contrib); 104 } 105 106 public void unregisterRedisPoolDescriptor(RedisPoolDescriptor contrib) { 107 registry.removeContribution(contrib); 108 } 109 110 @Override 111 public RedisPoolDescriptor getConfig() { 112 return registry.getConfig(); 113 } 114 115 @Override 116 public void start(ComponentContext context) { 117 RedisPoolDescriptor config = getConfig(); 118 if (config == null || config.disabled) { 119 return; 120 } 121 handleNewExecutor(config.newExecutor()); 122 } 123 124 @Override 125 public void stop(ComponentContext context) { 126 if (executor == null) { 127 return; 128 } 129 try { 130 executor.getPool().destroy(); 131 } finally { 132 executor = null; 133 } 134 } 135 136 @Override 137 public int getApplicationStartedOrder() { 138 return ((DefaultComponent) Framework.getRuntime() 139 .getComponentInstance("org.nuxeo.ecm.core.work.service") 140 .getInstance()).getApplicationStartedOrder() 141 - 1; 142 } 143 144 public void handleNewExecutor(RedisExecutor executor) { 145 this.executor = executor; 146 try { 147 delsha = load("org.nuxeo.ecm.core.redis", "del-keys"); 148 } catch (RuntimeException cause) { 149 executor = null; 150 throw new NuxeoException("Cannot activate redis executor", cause); 151 } 152 } 153 154 @Override 155 public Long clear(final String pattern) { 156 return (Long) executor.evalsha(delsha, Collections.singletonList(pattern), Collections.emptyList()); 157 } 158 159 @Override 160 public String load(String bundleName, String scriptName) { 161 Bundle b = Framework.getRuntime().getBundle(bundleName); 162 URL loc = b.getEntry(scriptName + ".lua"); 163 if (loc == null) { 164 throw new RuntimeException("Fail to load lua script: " + scriptName); 165 } 166 InputStream is; 167 final StrBuilder builder; 168 try { 169 is = loc.openStream(); 170 builder = new StrBuilder(); 171 for (String line : IOUtils.readLines(is)) { 172 builder.appendln(line); 173 } 174 } catch (IOException e) { 175 throw new RuntimeException("Fail to load lua script: " + scriptName, e); 176 } 177 178 return executor.scriptLoad(builder.toString()); 179 } 180 181 @Override 182 public <T> T getAdapter(Class<T> adapter) { 183 if (adapter.isAssignableFrom(RedisExecutor.class)) { 184 return adapter.cast(executor); 185 } 186 return super.getAdapter(adapter); 187 } 188 189 @Override 190 public String namespace(String... names) { 191 RedisPoolDescriptor config = getConfig(); 192 String prefix = config == null ? null : config.prefix; 193 if (StringUtils.isBlank(prefix)) { 194 prefix = DEFAULT_PREFIX; 195 } 196 StringBuilder builder = new StringBuilder(prefix); 197 for (String name : names) { 198 builder.append(name).append(":"); 199 } 200 return builder.toString(); 201 } 202 203}