001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.ejb.mbeans;
034:
035: import com.flexive.core.stream.BinaryDownloadProtocol;
036: import com.flexive.core.stream.BinaryUploadProtocol;
037: import com.flexive.core.structure.StructureLoader;
038: import com.flexive.shared.CacheAdmin;
039: import com.flexive.shared.FxContext;
040: import com.flexive.shared.cache.FxBackingCache;
041: import com.flexive.shared.cache.FxBackingCacheProvider;
042: import com.flexive.shared.cache.FxBackingCacheProviderFactory;
043: import com.flexive.shared.cache.FxCacheException;
044: import com.flexive.shared.mbeans.FxCacheMBean;
045: import com.flexive.shared.mbeans.MBeanHelper;
046: import com.flexive.shared.stream.FxStreamUtils;
047: import com.flexive.stream.ServerLocation;
048: import com.flexive.stream.StreamServer;
049: import org.apache.commons.logging.Log;
050: import org.apache.commons.logging.LogFactory;
051: import org.jboss.cache.Cache;
052:
053: import javax.management.*;
054: import java.util.ArrayList;
055: import java.util.List;
056: import java.util.Set;
057:
058: /**
059: * FxCache MBean
060: * TODO: implement missing skeletons ...
061: *
062: * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
063: */
064: //@Service(objectName = CacheAdmin.CACHE_SERVICE_NAME)
065: public class FxCache implements FxCacheMBean, DynamicMBean {
066: private static final transient Log LOG = LogFactory
067: .getLog(FxCache.class);
068:
069: private StreamServer server = null;
070: private long nodeStartupTime = -1;
071:
072: private FxBackingCacheProvider cacheProvider = null;
073:
074: /**
075: * Get the backing cache
076: *
077: * @return FxBackingCache
078: * @throws FxCacheException on errors
079: */
080: private FxBackingCache getBackingCache() throws FxCacheException {
081: if (cacheProvider == null) {
082: //start the cache
083: cacheProvider = FxBackingCacheProviderFactory.createNew();
084: LOG.info("Starting backing Cache {"
085: + cacheProvider.getDescription() + "}");
086: cacheProvider.init();
087: if (cacheProvider.getInstance().get(
088: "/" + this .getClass().getName(), SYSTEM_UP_KEY) == null) {
089: cacheProvider.getInstance().put(
090: "/" + this .getClass().getName(), SYSTEM_UP_KEY,
091: System.currentTimeMillis());
092: }
093: nodeStartupTime = System.currentTimeMillis();
094: }
095: return cacheProvider.getInstance();
096: }
097:
098: /**
099: * {@inheritDoc}
100: */
101: @SuppressWarnings("unchecked")
102: public void create() throws Exception {
103: if (server != null)
104: return;
105:
106: //switch to UTF-8 encoding
107: if (!"UTF-8".equals(System.getProperty("file.encoding"))) {
108: // set default charset to UTF-8
109: LOG.warn("Changing system character encoding from "
110: + System.getProperty("file.encoding")
111: + " to UTF-8.");
112: System.setProperty("file.encoding", "UTF-8");
113: }
114: //start streamserver
115: try {
116: server = new StreamServer(FxStreamUtils
117: .probeNetworkInterfaces(),
118: FxCacheMBean.STREAMING_PORT);
119: server.addProtocol(new BinaryUploadProtocol());
120: server.addProtocol(new BinaryDownloadProtocol());
121: server.start();
122: List<ServerLocation> servers = null;
123: if (globalExists(CacheAdmin.STREAMSERVER_BASE,
124: CacheAdmin.STREAMSERVER_EJB_KEY))
125: servers = (List<ServerLocation>) globalGet(
126: CacheAdmin.STREAMSERVER_BASE,
127: CacheAdmin.STREAMSERVER_EJB_KEY);
128: if (servers == null)
129: servers = new ArrayList<ServerLocation>(5);
130: ServerLocation this Server = new ServerLocation(server
131: .getAddress().getAddress(), server.getPort());
132: if (!servers.contains(this Server))
133: servers.add(this Server);
134: globalPut(CacheAdmin.STREAMSERVER_BASE,
135: CacheAdmin.STREAMSERVER_EJB_KEY, servers);
136: LOG.info("Added " + this Server
137: + " to available StreamServers (" + servers.size()
138: + " total)");
139: } catch (Exception e) {
140: LOG.error("Failed to start StreamServer. Error: "
141: + e.getMessage(), e);
142: }
143: }
144:
145: /**
146: * {@inheritDoc}
147: */
148: public void destroy() throws Exception {
149: //System.out.println("about to uninstall timer");
150: //EJBLookup.getTimerServiceInterface().uninstall();
151: //System.out.println("timers uninstalled");
152: if (server != null) {
153: LOG.info("Shutting down StreamServer {"
154: + server.getDescription() + "}");
155: try {
156: server.stop();
157: } catch (Exception e) {
158: LOG.error(e, e);
159: }
160: server = null;
161: }
162: try {
163: if (cacheProvider != null) {
164: cacheProvider.shutdown();
165: cacheProvider = null;
166: }
167: } catch (FxCacheException e) {
168: LOG.error(e, e);
169: }
170: }
171:
172: //TODO: finish me!
173: private static MBeanInfo info = new MBeanInfo(
174: FxCache.class.getCanonicalName(),
175: "[fleXive] Cache MBean",
176: new MBeanAttributeInfo[] { new MBeanAttributeInfo(
177: "FxCache", FxCache.class.getCanonicalName(), "",
178: true, false, false) },
179: new MBeanConstructorInfo[] {},
180: new MBeanOperationInfo[] {
181: new MBeanOperationInfo("get", "",
182: new MBeanParameterInfo[] {
183: new MBeanParameterInfo("path",
184: "java.lang.String", ""),
185: new MBeanParameterInfo("key",
186: "java.lang.Object", "") },
187: "java.lang.Object", MBeanOperationInfo.INFO),
188: new MBeanOperationInfo("put", "",
189: new MBeanParameterInfo[] {
190: new MBeanParameterInfo("path",
191: "java.lang.String", ""),
192: new MBeanParameterInfo("key",
193: "java.lang.Object", ""),
194: new MBeanParameterInfo("value",
195: "java.lang.Object", "") },
196: "void", MBeanOperationInfo.ACTION) },
197: new MBeanNotificationInfo[] {});
198:
199: /**
200: * {@inheritDoc}
201: */
202: public String getDeploymentId() {
203: return MBeanHelper.DEPLOYMENT_ID;
204: }
205:
206: /**
207: * Includes the division id into the path.
208: *
209: * @param path the path to encode
210: * @return the encoded path
211: * @throws FxCacheException if the division id could not be resolved
212: */
213: private String divisionEncodePath(String path)
214: throws FxCacheException {
215: try {
216: int divId;
217: //#<id> - purposely undocumented hack to force a division ;) - used during environment loading
218: if (path.charAt(0) == '#') {
219: try {
220: divId = Integer.parseInt(path.substring(1, path
221: .indexOf('/')));
222: path = path.substring(path.indexOf('/'));
223: } catch (Exception e) {
224: throw new FxCacheException(
225: "Invalid Division Id in path [" + path
226: + "]!");
227: }
228: } else {
229: FxContext ri = FxContext.get();
230: if (ri.getDivisionId() == -1) {
231: throw new FxCacheException(
232: "Division ID missing in request information ["
233: + ri.getRequestURI() + "]");
234: }
235: divId = ri.getDivisionId();
236: }
237: return "/Division" + divId
238: + (path.startsWith("/") ? "" : "/") + path;
239: } catch (Throwable t) {
240: System.err.println(t.getMessage());
241: throw new FxCacheException("Unable to encode path: "
242: + t.getMessage());
243: }
244: }
245:
246: /**
247: * Includes the global division id into the path.
248: *
249: * @param path the path to encode
250: * @return the encoded path
251: */
252: private String globalDivisionEncodePath(final String path) {
253: return "/GlobalConfiguration"
254: + (path.startsWith("/") ? "" : "/") + path;
255: }
256:
257: /**
258: * {@inheritDoc}
259: */
260: public Cache<Object, Object> getCache() throws FxCacheException {
261: return getBackingCache().getCache();
262: }
263:
264: /**
265: * {@inheritDoc}
266: */
267: public Object get(String path, Object key) throws FxCacheException {
268: return getBackingCache().get(divisionEncodePath(path), key);
269: }
270:
271: /**
272: * {@inheritDoc}
273: */
274: public Object globalGet(String path, Object key)
275: throws FxCacheException {
276: return getBackingCache().get(globalDivisionEncodePath(path),
277: key);
278: }
279:
280: /**
281: * {@inheritDoc}
282: */
283: public boolean globalExists(String path, Object key)
284: throws FxCacheException {
285: return getBackingCache().exists(globalDivisionEncodePath(path),
286: key);
287: }
288:
289: /**
290: * {@inheritDoc}
291: */
292: public void put(String path, Object key, Object value)
293: throws FxCacheException {
294: getBackingCache().put(divisionEncodePath(path), key, value);
295: }
296:
297: /**
298: * {@inheritDoc}
299: */
300: public boolean exists(String path, Object key)
301: throws FxCacheException {
302: return getBackingCache().exists(divisionEncodePath(path), key);
303: }
304:
305: /**
306: * {@inheritDoc}
307: */
308: public void globalPut(String path, Object key, Object value)
309: throws FxCacheException {
310: getBackingCache().put(globalDivisionEncodePath(path), key,
311: value);
312: }
313:
314: /**
315: * {@inheritDoc}
316: */
317: public void remove(String path) throws FxCacheException {
318: getBackingCache().remove(divisionEncodePath(path));
319: }
320:
321: /**
322: * {@inheritDoc}
323: */
324: public void globalRemove(String path) throws FxCacheException {
325: getBackingCache().remove(globalDivisionEncodePath(path));
326: }
327:
328: /**
329: * {@inheritDoc}
330: */
331: public Set getKeys(String path) throws FxCacheException {
332: return getBackingCache().getKeys(divisionEncodePath(path));
333: }
334:
335: /**
336: * {@inheritDoc}
337: */
338: public Set globalGetKeys(String path) throws FxCacheException {
339: return getBackingCache()
340: .getKeys(globalDivisionEncodePath(path));
341: }
342:
343: /**
344: * {@inheritDoc}
345: */
346: public Set getChildrenNames(String path) throws FxCacheException {
347: return getBackingCache().getChildrenNames(
348: divisionEncodePath(path));
349: }
350:
351: /**
352: * {@inheritDoc}
353: */
354: public void remove(String path, Object key) throws FxCacheException {
355: getBackingCache().remove(divisionEncodePath(path), key);
356: }
357:
358: /**
359: * {@inheritDoc}
360: */
361: public void globalRemove(String path, Object key)
362: throws FxCacheException {
363: getBackingCache().remove(globalDivisionEncodePath(path), key);
364: }
365:
366: /**
367: * {@inheritDoc}
368: */
369: public void reloadEnvironment(Integer divisionId) throws Exception {
370: StructureLoader.load(divisionId, true, null);
371: }
372:
373: /**
374: * {@inheritDoc}
375: */
376: public void setEvictionStrategy(Integer divisionId, String path,
377: Integer maxContents, Integer timeToIdle, Integer timeToLive)
378: throws FxCacheException {
379: cacheProvider.setEvictionStrategy("/Division" + divisionId
380: + (path.charAt(0) == '/' ? path : '/' + path),
381: maxContents, timeToIdle, timeToLive);
382: }
383:
384: /**
385: * {@inheritDoc}
386: */
387: public long getSystemStartTime() {
388: try {
389: return (Long) getBackingCache().get(
390: "/" + this .getClass().getName(), SYSTEM_UP_KEY);
391: } catch (Exception exc) {
392: return -1;
393: }
394: }
395:
396: /**
397: * {@inheritDoc}
398: */
399: public long getNodeStartTime() {
400: return nodeStartupTime;
401: }
402:
403: /**
404: * {@inheritDoc}
405: */
406: public Object getAttribute(String attribute)
407: throws AttributeNotFoundException, MBeanException,
408: ReflectionException {
409: /*if ("FxCache".equals(attribute))
410: return getCache();
411: else*/
412: if ("DeploymentId".equals(attribute))
413: return getDeploymentId();
414: else if ("SystemStartTime".equals(attribute))
415: return getSystemStartTime();
416: else if ("NodeStartTime".equals(attribute))
417: return getNodeStartTime();
418: return null; //To change body of implemented methods use File | Settings | File Templates.
419: }
420:
421: /**
422: * {@inheritDoc}
423: */
424: public void setAttribute(Attribute attribute)
425: throws AttributeNotFoundException,
426: InvalidAttributeValueException, MBeanException,
427: ReflectionException {
428: //TODO: code me!
429: }
430:
431: /**
432: * {@inheritDoc}
433: */
434: public AttributeList getAttributes(String[] attributes) {
435: //TODO: code me!
436: return null;
437: }
438:
439: /**
440: * {@inheritDoc}
441: */
442: public AttributeList setAttributes(AttributeList attributes) {
443: //TODO: code me!
444: return null;
445: }
446:
447: /**
448: * {@inheritDoc}
449: */
450: public Object invoke(String actionName, Object params[],
451: String signature[]) throws MBeanException,
452: ReflectionException {
453: try {
454: if ("get".equals(actionName)) {
455: return get((String) params[0], params[1]);
456: } else if ("put".equals(actionName)) {
457: put((String) params[0], params[1], params[2]);
458: } else if ("remove".equals(actionName)
459: && params.length == 1) {
460: remove((String) params[0]);
461: } else if ("remove".equals(actionName)
462: && params.length == 2) {
463: remove((String) params[0], params[1]);
464: } else if ("exists".equals(actionName)
465: && params.length == 2) {
466: return exists((String) params[0], params[1]);
467: } else if ("getKeys".equals(actionName)) {
468: return getKeys((String) params[0]);
469: } else if ("globalGet".equals(actionName)) {
470: return globalGet((String) params[0], params[1]);
471: } else if ("globalPut".equals(actionName)) {
472: globalPut((String) params[0], params[1], params[2]);
473: } else if ("globalRemove".equals(actionName)
474: && params.length == 1) {
475: globalRemove((String) params[0]);
476: } else if ("globalRemove".equals(actionName)
477: && params.length == 2) {
478: globalRemove((String) params[0], params[1]);
479: } else if ("globalExists".equals(actionName)
480: && params.length == 2) {
481: return globalExists((String) params[0], params[1]);
482: } else if ("globalGetKeys".equals(actionName)
483: && params.length == 1) {
484: return globalGetKeys((String) params[0]);
485: } else if ("getChildrenNames".equals(actionName)) {
486: return getChildrenNames((String) params[0]);
487: } else if ("reloadEnvironment".equals(actionName)) {
488: reloadEnvironment((Integer) params[0]);
489: } else if ("create".equals(actionName)) {
490: create();
491: } else if ("destroy".equals(actionName)) {
492: destroy();
493: } else if ("setEvictionStrategy".equals(actionName)
494: && params.length == 5) {
495: setEvictionStrategy((Integer) params[0],
496: (String) params[1], (Integer) params[2],
497: (Integer) params[3], (Integer) params[4]);
498: } else {
499: LOG.warn("Tried to call [" + actionName
500: + "] which is not implemented!");
501: }
502: } catch (Exception e) {
503: LOG
504: .error("Failed to invoke MBean op: "
505: + e.getMessage(), e);
506: throw new MBeanException(e);
507: }
508: return null; //To change body of implemented methods use File | Settings | File Templates.
509: }
510:
511: public MBeanInfo getMBeanInfo() {
512: return info;
513: }
514: }
|