/* * Weblounge: Web Content Management System * Copyright (c) 2003 - 2011 The Weblounge Team * http://entwinemedia.com/weblounge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ch.entwine.weblounge.cache.impl.command; import ch.entwine.weblounge.cache.impl.CacheConfiguration; import ch.entwine.weblounge.cache.impl.CacheConfigurationFactory; import ch.entwine.weblounge.cache.impl.CacheServiceImpl; import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.text.DecimalFormat; import java.util.Arrays; import java.util.Dictionary; import java.util.Enumeration; import java.util.Hashtable; /** * OSGi shell command implementation for the cache. */ public class CacheCommand { /** Logger */ private static final Logger logger = LoggerFactory.getLogger(CacheCommand.class); /** The cache configuration factory */ private CacheConfigurationFactory configFactory = null; /** * Command signature that allows to do * <ul> * <li><code>cache list</code></li> * <li><code>cache <id> status</code></li> * <li><code>cache <id> enable</code></li> * <li><code>cache <id> disable</code></li> * <li><code>cache <id> clear</code></li> * <li><code>cache <id> get <property></code></li> * <li><code>cache <id> set <property> <value></code></li> * <li><code>cache <id> get <property></code></li> * </ul> * * @param args * the list of arguments to this command */ public synchronized void cache(String[] args) { if (configFactory == null) { System.out.println("Cache service not found"); return; } if (args.length == 0) { list(); return; } else if (args.length == 1) { if ("list".equals(args[0])) { list(); } else { printUsage(); } } else if (args.length > 1) { String id = args[0]; // Look up the cache CacheConfiguration config = getCache(id); if (config == null) { try { config = getCache(Integer.parseInt(id)); if (config == null) { System.out.println("Unknown cache: " + id); return; } } catch (NumberFormatException e) { System.out.println("Unknown cache: " + id); return; } } // Process the command if ("enable".equals(args[1])) enable(config); else if ("disable".equals(args[1])) disable(config); else if ("clear".equals(args[1])) clear(config); else if ("status".equals(args[1])) status(config); else if ("get".equals(args[1])) get(config, Arrays.copyOfRange(args, 2, args.length)); else if ("set".equals(args[1])) { set(config, Arrays.copyOfRange(args, 2, args.length)); } else { System.out.println("Unknown command: " + args[1]); return; } } else { printUsage(); } } /** * Prints a list of currently registered cache configurations. */ private void list() { CacheConfiguration[] configurations = configFactory.getConfigurations(); // Are there any cache configurations? if (configurations.length == 0) { System.out.println("No cache instances found"); return; } // Setup the number formatter int digits = 1 + (int) (Math.log(configurations.length + 1) / Math.log(10)); StringBuffer format = new StringBuffer(); for (int i = 0; i < digits; i++) format.append("#"); DecimalFormat formatter = new DecimalFormat(format.toString()); // Display the cache list for (int i = 0; i < configurations.length; i++) { CacheConfiguration configuration = configurations[i]; String id = configuration.getIdentifier(); String name = configuration.getName(); boolean enabled = configuration.isEnabled(); StringBuffer buf = new StringBuffer(); buf.append("[ ").append(formatter.format(i + 1)).append(" ] "); while (buf.length() < 8) buf.append(" "); buf.append(name != null ? name : id); buf.append(" "); int descriptionLength = buf.length(); for (int j = 0; j < 64 - descriptionLength; j++) buf.append("."); buf.append(enabled ? " ENABLED " : " DISABLED"); while (buf.length() < 22) buf.append(" "); System.out.println(buf.toString()); } } /** * Prints out information about the cache. * * @param cache * the cache */ private void status(CacheConfiguration cache) { Dictionary<?, ?> properties = cache.getProperties(); for (Enumeration<?> keyEnum = properties.keys(); keyEnum.hasMoreElements();) { String key = keyEnum.nextElement().toString(); String keyPresentation = key; if ("service.pid".equals(key)) continue; else if (CacheServiceImpl.OPT_ID.equals(key)) continue; else if (CacheServiceImpl.OPT_NAME.equals(key)) continue; else if (key.startsWith(CacheServiceImpl.OPT_PREFIX)) keyPresentation = key.substring(CacheServiceImpl.OPT_PREFIX.length() + 1); String object = cache.getProperties().get(key).toString(); pad(keyPresentation, object); } } /** * Returns the cache configuration property identified by the first (and only) * item in <code>args</code>. * * @param configuration * the cache configuration * @param args * the arguments */ private void get(CacheConfiguration configuration, String[] args) { if (args.length != 1) { System.out.println("Please specify a configuration tkey"); System.err.println("Usage: cache <id> get <key>"); return; } String key = CacheServiceImpl.OPT_PREFIX + "." + args[0]; String value = (String) configuration.getProperties().get(key); if (value != null) { System.out.println(value); } } /** * Returns the cache configuration property identified by the first (and only) * item in <code>args</code>. * * @param configuration * the cache configuration * @param args * the arguments */ private void set(CacheConfiguration configuration, String[] args) { if (args.length < 1) { System.out.println("Please specify a configuration key"); System.err.println("Usage: cache <id> set <key> <value>"); return; } else if (!configuration.isEnabled()) { System.out.println("This cache is not enabled"); return; } String id = configuration.getIdentifier(); String key = CacheServiceImpl.OPT_PREFIX + "." + args[0]; if (args.length > 1) { configuration.getProperties().put(key, args[1]); } else { configuration.getProperties().remove(key); } // Tell the configuration admin service to update the service try { configuration.getConfiguration().update(configuration.getProperties()); } catch (IOException e) { System.out.println("Error updating cache '" + id + "': " + e.getMessage()); } } /** * Clears the contents of the cache. * * @param configuration * the cache configuration */ private void clear(CacheConfiguration configuration) { if (!configuration.isEnabled()) { System.out.println("This cache is not enabled"); return; } Dictionary<Object, Object> properties = configuration.getProperties(); String id = (String) properties.get(CacheServiceImpl.OPT_ID); properties.put(CacheServiceImpl.OPT_CLEAR, "true"); // Tell the configuration admin service to update the service try { configuration.getConfiguration().update(properties); properties.remove(CacheServiceImpl.OPT_CLEAR); configuration.getConfiguration().update(properties); } catch (IOException e) { System.out.println("Error updating cache '" + id + "': " + e.getMessage()); } } /** * Returns a padded version of the text. * * @param caption * the caption * @param info * the information */ private void pad(String caption, String info) { if (caption == null) caption = ""; for (int i = 0; i < (20 - caption.length()); i++) System.out.print(" "); if (!"".equals(caption)) { System.out.print(caption); System.out.print(": "); } else { System.out.print(" "); } System.out.print(info); System.out.println(); } /** * Enables the cache. * * @param configuration * the cache to enable */ private void enable(CacheConfiguration configuration) { if (configuration.isEnabled()) { System.out.println("Cache " + configuration + " is already enabled"); return; } try { configFactory.enable(configuration); } catch (Throwable t) { t.printStackTrace(); } } /** * Disables the cache. * * @param configuration * the cache to disable */ private void disable(CacheConfiguration configuration) { if (!configuration.isEnabled()) { System.out.println("Cache " + configuration + " is already disbled"); return; } try { configFactory.disable(configuration); } catch (Throwable t) { t.printStackTrace(); } } /** * Prints the command usage to the commandline. */ private void printUsage() { System.out.println(" Usage:"); System.out.println(" cache list"); System.out.println(" cache <id> enable | disable"); System.out.println(" cache <id> clear"); System.out.println(" cache <id> status"); System.out.println(" cache <id> get <property>"); System.out.println(" cache <id> set <property> <value>"); } /** * Returns the configuration of the cache with the given identifier or * <code>null</code> if no such cache was registered. * * @param id * the cache identifier * @return the cache configuration */ private CacheConfiguration getCache(String id) { return configFactory.getConfiguration(id); } /** * Returns the cache configuration with the given index or <code>null</code> * if a wrong index is given. * * @param index * the cache configuration number * @return the cache configuration */ private CacheConfiguration getCache(int index) { index--; CacheConfiguration[] configurations = configFactory.getConfigurations(); return (index < configurations.length) ? configurations[index] : null; } /** * Callback for OSGi's declarative services component dactivation. * * @param context * the component context * @throws Exception * if component inactivation fails */ void activate(ComponentContext context) throws Exception { BundleContext bundleContext = context.getBundleContext(); logger.debug("Registering cache commands"); Dictionary<String, Object> commands = new Hashtable<String, Object>(); commands.put("osgi.command.scope", "weblounge"); commands.put("osgi.command.function", new String[] { "cache" }); bundleContext.registerService(getClass().getName(), this, commands); } /** * Callback from the OSGi declarative services environment that will pass in a * reference to the cache configuration factory. * * @param factory * the configuration factory */ synchronized void setCacheConfigurationFactory( CacheConfigurationFactory factory) { configFactory = factory; } /** * Callback from the OSGi declarative services environment to indicate that * the reference to the cache configuration factory is no longer valid. * * @param factory * the configuration factory */ synchronized void removeCacheConfigurationFactory( CacheConfigurationFactory factory) { configFactory = null; } }