001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo;
012:
013: import com.versant.core.common.config.ConfigInfo;
014: import com.versant.core.util.BeanUtils;
015: import com.versant.core.util.StringListParser;
016: import com.versant.core.util.PropertiesLoader;
017: import com.versant.core.util.classhelper.ClassHelper;
018: import com.versant.core.common.BindingSupportImpl;
019: import com.versant.core.metric.*;
020: import com.versant.core.metric.HasMetrics;
021: import com.versant.core.logging.LogEvent;
022: import com.versant.core.storagemanager.StorageManagerFactory;
023: import com.versant.core.storagemanager.StorageManagerFactoryBuilder;
024:
025: import javax.jdo.PersistenceManagerFactory;
026: import java.util.*;
027: import java.io.IOException;
028:
029: /**
030: * PMF implementation.
031: */
032: public class PersistenceManagerFactoryImp extends
033: PersistenceManagerFactoryBase implements HasMetrics {
034:
035: protected Map hyperdriveBytecode;
036: protected int hyperdriveBytecodeMaxSize;
037: protected VersantBackgroundTask logDownloader;
038: protected Thread logDownloaderThread;
039: protected PMFServer[] pmfServers;
040: protected boolean releaseHyperdriveBytecode;
041:
042: protected MetricSnapshotStore metricSnapshotStore;
043: protected HashMap userMetricIndexMap;
044: protected BaseMetric[] userMetrics;
045: protected int[] userMetricValues;
046:
047: public static final String PMF_SERVER = "pmf.server";
048: public static final String RELEASE_HYPERDRIVE_BYTECODE = "versant.releaseHyperdriveBytecode";
049:
050: private static final String CAT_GENERAL = "General";
051:
052: private final BaseMetric metricEvents = new BaseMetric("Events",
053: "Events", CAT_GENERAL, "Number of events logged", 3,
054: Metric.CALC_DELTA_PER_SECOND);
055: private final BaseMetric metricLastEventId = new BaseMetric(
056: "LastEventId", "Last Event ID", CAT_GENERAL,
057: "Approximate ID of the last event logged", 0,
058: Metric.CALC_RAW);
059:
060: private static final String CAT_PM = "PM";
061:
062: private final BaseMetric metricPMCreated = new BaseMetric(
063: "PMCreated", "PM Created", CAT_PM,
064: "Number of local PMs created", 3,
065: Metric.CALC_DELTA_PER_SECOND);
066: private final BaseMetric metricPMClosed = new BaseMetric(
067: "PMClosed", "PM Closed", CAT_PM,
068: "Number of PMs closed (local and remote)", 3,
069: Metric.CALC_DELTA_PER_SECOND);
070: private final BaseMetric metricPMClosedAuto = new BaseMetric(
071: "PMClosedAuto", "PM Closed Auto", CAT_PM,
072: "Number of PMs closed automatically (local and remote)", 0,
073: Metric.CALC_RAW);
074: private final BaseMetric metricPMClosedAutoTx = new BaseMetric(
075: "PMClosedAutoTx",
076: "PM Closed Auto Tx",
077: CAT_PM,
078: "Number of PMs closed automatically with active datastore transaction (BAD)",
079: 0, Metric.CALC_RAW);
080: private final BaseMetric metricPMCount = new BaseMetric("PMCount",
081: "PM Count", CAT_PM, "Number of open PMs", 0,
082: Metric.CALC_AVERAGE);
083:
084: /**
085: * This is called by JDOHelper to construct a PM factory from a properties
086: * instance.
087: */
088: public static PersistenceManagerFactory getPersistenceManagerFactory(
089: Properties props) {
090: return new PersistenceManagerFactoryImp(props,
091: PersistenceManagerFactoryImp.class.getClassLoader());
092: }
093:
094: public PersistenceManagerFactoryImp(Properties props,
095: ClassLoader loader) {
096: super (props, loader);
097: boolean ok = false;
098: try {
099: initLogDownloader(config, loader);
100: initMetrics(config);
101: if (pmfServers != null) {
102: for (int i = 0; i < pmfServers.length; i++) {
103: PMFServer s = pmfServers[i];
104: s.init(this );
105: if (s instanceof HasMetrics) {
106: metricSnapshotStore.addSource((HasMetrics) s);
107: }
108: }
109: }
110: startLogDownloader(config);
111: metricSnapshotStore.start(config.url);
112: if (pmfServers != null) {
113: for (int i = 0; i < pmfServers.length; i++) {
114: try {
115: pmfServers[i].start();
116: } catch (Exception e) {
117: throw handleException(e);
118: }
119: }
120: }
121: ok = true;
122: } finally {
123: if (!ok) {
124: try {
125: close();
126: } catch (Throwable e) {
127: // ignore - already busy with an exception
128: }
129: }
130: }
131: }
132:
133: /**
134: * Create our StorageManagerFactory.
135: */
136: protected StorageManagerFactory createStorageManagerFactory() {
137: createPMFServers();
138: releaseHyperdriveBytecode = pmfServers == null
139: && "true".equals(props
140: .getProperty(RELEASE_HYPERDRIVE_BYTECODE));
141: StorageManagerFactoryBuilder b = new StorageManagerFactoryBuilder();
142: b.setLogEventStore(pes);
143: b.setConfig(config);
144: b.setLoader(loader);
145: b.setCache(cache);
146: b.setKeepHyperdriveBytecode(!releaseHyperdriveBytecode);
147: StorageManagerFactory ans = b.createStorageManagerFactory();
148: hyperdriveBytecode = b.getHyperdriveBytecode();
149: hyperdriveBytecodeMaxSize = b.getHyperdriveBytecodeMaxSize();
150: return ans;
151: }
152:
153: public void addPMFServer(PMFServer pmfServer) {
154: if (releaseHyperdriveBytecode && config.hyperdrive) {
155: throw BindingSupportImpl.getInstance().invalidOperation(
156: "Unable to add PMFServer as versant.releaseHyperdriveBytecode "
157: + "property is true");
158: }
159: addPMFServerImp(pmfServer);
160: if (pmfServer instanceof HasMetrics) {
161: metricSnapshotStore.addSource((HasMetrics) pmfServer);
162: }
163: }
164:
165: protected void addPMFServerImp(PMFServer pmfServer) {
166: if (pmfServers == null) {
167: pmfServers = new PMFServer[] { pmfServer };
168: } else {
169: int n = pmfServers.length;
170: PMFServer[] a = new PMFServer[n + 1];
171: System.arraycopy(pmfServers, 0, a, 0, n);
172: a[n] = pmfServer;
173: pmfServers = a;
174: }
175: }
176:
177: /**
178: * Export us using whatever remote access protocols have been specified.
179: */
180: protected void createPMFServers() {
181: String ra = config.remoteAccess;
182: if (ra == null || "true".equals(ra)) {
183: ra = "socket";
184: } else if ("false".equals(ra)) {
185: return;
186: }
187: boolean defaultProtocol = "socket".equals(ra);
188: for (StringListParser lp = new StringListParser(ra); lp
189: .hasNext();) {
190: String protocol = lp.nextString();
191: PMFServer pmfServer = createPMFServer(protocol,
192: defaultProtocol);
193: if (pmfServer != null) {
194: addPMFServerImp(pmfServer);
195: }
196: }
197: }
198:
199: /**
200: * Create a PMFServer instance to handle the protocol. If defaultProtocol
201: * is true and the properties resource for the protocol cannot be loaded
202: * then null is returned. Otherwise an exception is thrown. This handles
203: * the case where remote access is on by default but the remote access
204: * module is not available.
205: */
206: private PMFServer createPMFServer(String protocol,
207: boolean defaultProtocol) {
208: Properties p;
209: try {
210: p = PropertiesLoader.loadProperties(loader,
211: "openaccess-remote", protocol);
212: } catch (IOException e) {
213: if (defaultProtocol) {
214: return null;
215: }
216: throw BindingSupportImpl.getInstance().invalidOperation(
217: e.toString(), e);
218: }
219: String clsName = p.getProperty(PMF_SERVER);
220: if (clsName == null) {
221: throw BindingSupportImpl
222: .getInstance()
223: .internal(
224: PMF_SERVER
225: + " not found in resource "
226: + p
227: .getProperty(PropertiesLoader.RES_NAME_PROP));
228: }
229: try {
230: Class cls = ClassHelper.get().classForName(clsName, true,
231: loader);
232: return (PMFServer) cls.newInstance();
233: } catch (Exception e) {
234: throw BindingSupportImpl.getInstance().internal(
235: e.toString(), e);
236: }
237: }
238:
239: protected void initMetrics(ConfigInfo config) {
240: int n = config.userBaseMetrics.size();
241: if (n > 0) {
242: userMetricValues = new int[n];
243: userMetricIndexMap = new HashMap(n * 2);
244: userMetrics = new BaseMetric[n];
245: for (int i = 0; i < n; i++) {
246: ConfigInfo.UserBaseMetric u = (ConfigInfo.UserBaseMetric) config.userBaseMetrics
247: .get(i);
248: BaseMetric m = new BaseMetric(u.name, u.displayName,
249: u.category, u.description, u.decimals,
250: u.defaultCalc);
251: userMetricIndexMap.put(m.getName(), new Integer(i));
252: userMetrics[i] = m;
253: }
254: }
255: metricSnapshotStore = new MetricSnapshotStore(
256: config.metricStoreCapacity,
257: config.metricSnapshotIntervalMs);
258: metricSnapshotStore.addSource(this );
259: }
260:
261: protected void startLogDownloader(ConfigInfo config) {
262: logDownloaderThread = new Thread(logDownloader,
263: "VOA Log Downloader " + config.url);
264: logDownloaderThread.setDaemon(true);
265: logDownloaderThread.start();
266: }
267:
268: protected void initLogDownloader(ConfigInfo config,
269: ClassLoader loader) {
270: try {
271: if (config.logDownloaderClass == null) {
272: logDownloader = new LogDownloader();
273: } else {
274: logDownloader = (VersantBackgroundTask) BeanUtils
275: .newInstance(config.logDownloaderClass, loader,
276: VersantBackgroundTask.class);
277: }
278: BeanUtils.setProperties(logDownloader,
279: config.logDownloaderProps);
280: if (logDownloader instanceof LogDownloader) {
281: ((LogDownloader) logDownloader).setQuiet(true);
282: }
283: logDownloader.setPmf(this );
284: } catch (Exception e) {
285: throw handleException(e);
286: }
287: }
288:
289: public synchronized void close() {
290: super .close();
291: if (pmfServers != null) {
292: for (int i = 0; i < pmfServers.length; i++) {
293: try {
294: pmfServers[i].close();
295: } catch (Throwable e) {
296: // ignore
297: }
298: }
299: }
300: if (logDownloaderThread != null) {
301: logDownloader.shutdown();
302: logDownloaderThread.interrupt();
303: logDownloaderThread = null;
304: }
305: if (metricSnapshotStore != null) {
306: metricSnapshotStore.shutdown();
307: metricSnapshotStore = null;
308: }
309: }
310:
311: public Metric[] getMetrics() {
312: return metricSnapshotStore.getMetrics();
313: }
314:
315: public MetricSnapshotPacket getNewMetricSnapshots(int lastId) {
316: return metricSnapshotStore.getNewSnapshots(lastId);
317: }
318:
319: public MetricSnapshotPacket getMostRecentMetricSnapshot(int lastId) {
320: return metricSnapshotStore.getMostRecentSnapshot(lastId);
321: }
322:
323: protected int findUserMetricIndex(String name) {
324: Integer ans = (Integer) userMetricIndexMap.get(name);
325: if (ans == null) {
326: throw BindingSupportImpl.getInstance().invalidOperation(
327: "Unknown user-defined Metric: '" + name + "'");
328: }
329: return ans.intValue();
330: }
331:
332: public void setUserMetric(String name, int value) {
333: userMetricValues[findUserMetricIndex(name)] = value;
334: }
335:
336: public synchronized void incUserMetric(String name, int delta) {
337: userMetricValues[findUserMetricIndex(name)] += delta;
338: }
339:
340: public int getUserMetric(String name) {
341: return userMetricValues[findUserMetricIndex(name)];
342: }
343:
344: public void addMetrics(List list) {
345: list.add(metricEvents);
346: list.add(metricLastEventId);
347: list.add(metricPMCreated);
348: list.add(metricPMClosed);
349: list.add(metricPMClosedAuto);
350: list.add(metricPMClosedAutoTx);
351: list.add(metricPMCount);
352: if (pmPool != null) {
353: pmPool.addMetrics(list);
354: }
355: if (smf instanceof HasMetrics) {
356: ((HasMetrics) smf).addMetrics(list);
357: }
358: if (userMetrics != null) {
359: list.addAll(Arrays.asList(userMetrics));
360: }
361: }
362:
363: public void sampleMetrics(int[][] buf, int pos) {
364: buf[metricEvents.getIndex()][pos] = pes.getEventsLogged();
365: buf[metricLastEventId.getIndex()][pos] = LogEvent.getLastId();
366: buf[metricPMCreated.getIndex()][pos] = pmCreatedCount;
367: buf[metricPMClosed.getIndex()][pos] = pmClosedCount;
368: buf[metricPMClosedAuto.getIndex()][pos] = pmClosedAutoCount;
369: buf[metricPMClosedAutoTx.getIndex()][pos] = pmClosedAutoTxCount;
370: buf[metricPMCount.getIndex()][pos] = activePMs.size();
371: if (pmPool != null) {
372: pmPool.sampleMetrics(buf, pos);
373: }
374: if (smf instanceof HasMetrics) {
375: ((HasMetrics) smf).sampleMetrics(buf, pos);
376: }
377: if (userMetrics != null) {
378: for (int i = userMetrics.length - 1; i >= 0; i--) {
379: buf[userMetrics[i].getIndex()][pos] = userMetricValues[i];
380: }
381: }
382: }
383:
384: public Map getHyperdriveBytecode() {
385: return hyperdriveBytecode;
386: }
387:
388: public int getHyperdriveBytecodeMaxSize() {
389: return hyperdriveBytecodeMaxSize;
390: }
391:
392: public boolean isLocal() {
393: return true;
394: }
395:
396: }
|