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.runtime.api.Framework; 030import org.nuxeo.runtime.model.ComponentContext; 031import org.nuxeo.runtime.model.ComponentInstance; 032import org.nuxeo.runtime.model.DefaultComponent; 033import org.nuxeo.runtime.model.SimpleContributionRegistry; 034import org.osgi.framework.Bundle; 035 036/** 037 * Implementation of the Redis Service holding the configured Jedis pool. 038 * 039 * @since 5.8 040 */ 041public class RedisComponent extends DefaultComponent implements RedisAdmin { 042 043 private static final String DEFAULT_PREFIX = "nuxeo:"; 044 045 protected volatile RedisExecutor executor; 046 047 protected RedisPoolDescriptorRegistry registry = new RedisPoolDescriptorRegistry(); 048 049 public static class RedisPoolDescriptorRegistry extends SimpleContributionRegistry<RedisPoolDescriptor> { 050 051 protected RedisPoolDescriptor config; 052 053 @Override 054 public String getContributionId(RedisPoolDescriptor contrib) { 055 return "main"; 056 } 057 058 @Override 059 public void contributionUpdated(String id, RedisPoolDescriptor contrib, RedisPoolDescriptor newOrigContrib) { 060 config = contrib; 061 } 062 063 @Override 064 public void contributionRemoved(String id, RedisPoolDescriptor origContrib) { 065 config = null; 066 } 067 068 public RedisPoolDescriptor getConfig() { 069 return config; 070 } 071 072 public void clear() { 073 config = null; 074 } 075 } 076 077 protected String delsha; 078 079 @Override 080 public void activate(ComponentContext context) { 081 super.activate(context); 082 registry.clear(); 083 } 084 085 @Override 086 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 087 if (contribution instanceof RedisPoolDescriptor) { 088 registerRedisPoolDescriptor((RedisPoolDescriptor) contribution); 089 } else { 090 throw new RuntimeException("Unknown contribution class: " + contribution); 091 } 092 } 093 094 @Override 095 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 096 if (contribution instanceof RedisPoolDescriptor) { 097 unregisterRedisPoolDescriptor((RedisPoolDescriptor) contribution); 098 } 099 } 100 101 public void registerRedisPoolDescriptor(RedisPoolDescriptor contrib) { 102 registry.addContribution(contrib); 103 } 104 105 public void unregisterRedisPoolDescriptor(RedisPoolDescriptor contrib) { 106 registry.removeContribution(contrib); 107 } 108 109 @Override 110 public RedisPoolDescriptor getConfig() { 111 return registry.getConfig(); 112 } 113 114 @Override 115 public void start(ComponentContext context) { 116 RedisPoolDescriptor config = getConfig(); 117 if (config == null || config.disabled) { 118 return; 119 } 120 handleNewExecutor(config.newExecutor()); 121 } 122 123 @Override 124 public void stop(ComponentContext context) { 125 if (executor == null) { 126 return; 127 } 128 try { 129 executor.getPool().destroy(); 130 } finally { 131 executor = null; 132 } 133 } 134 135 @Override 136 public int getApplicationStartedOrder() { 137 return ((DefaultComponent) Framework.getRuntime() 138 .getComponentInstance("org.nuxeo.ecm.core.work.service") 139 .getInstance()).getApplicationStartedOrder() 140 - 1; 141 } 142 143 public void handleNewExecutor(RedisExecutor executor) { 144 this.executor = executor; 145 try { 146 delsha = load("org.nuxeo.runtime.redis", "del-keys"); 147 } catch (RuntimeException cause) { 148 executor = null; 149 throw new RuntimeException("Cannot activate redis executor", cause); 150 } 151 } 152 153 @Override 154 public Long clear(final String pattern) { 155 return (Long) executor.evalsha(delsha, Collections.singletonList(pattern), Collections.emptyList()); 156 } 157 158 @Override 159 public String load(String bundleName, String scriptName) { 160 Bundle b = Framework.getRuntime().getBundle(bundleName); 161 URL loc = b.getEntry(scriptName + ".lua"); 162 if (loc == null) { 163 throw new RuntimeException("Fail to load lua script: " + scriptName); 164 } 165 InputStream is; 166 final StrBuilder builder; 167 try { 168 is = loc.openStream(); 169 builder = new StrBuilder(); 170 for (String line : IOUtils.readLines(is)) { 171 builder.appendln(line); 172 } 173 } catch (IOException e) { 174 throw new RuntimeException("Fail to load lua script: " + scriptName, e); 175 } 176 177 return executor.scriptLoad(builder.toString()); 178 } 179 180 @Override 181 public <T> T getAdapter(Class<T> adapter) { 182 if (adapter.isAssignableFrom(RedisExecutor.class)) { 183 return adapter.cast(executor); 184 } 185 return super.getAdapter(adapter); 186 } 187 188 @Override 189 public String namespace(String... names) { 190 RedisPoolDescriptor config = getConfig(); 191 String prefix = config == null ? null : config.prefix; 192 if (StringUtils.isBlank(prefix)) { 193 prefix = DEFAULT_PREFIX; 194 } 195 StringBuilder builder = new StringBuilder(prefix); 196 for (String name : names) { 197 builder.append(name).append(":"); 198 } 199 return builder.toString(); 200 } 201 202}