Java tutorial
/* * jPOS Project [http://jpos.org] * Copyright (C) 2000-2016 Alejandro P. Revilla * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.jpos.transaction; import org.jdom2.Element; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; import org.jpos.iso.ISOUtil; import org.jpos.util.LogEvent; import org.jpos.util.Loggeable; import org.jpos.util.Profiler; import java.io.*; import java.util.*; @SuppressWarnings("unchecked") public class Context implements Externalizable, Loggeable, Pausable { private transient Map<String, Object> map; // transient map private Map<String, Object> pmap; // persistent (serializable) map private long timeout; private boolean resumeOnPause = false; private transient boolean trace = false; public static String LOGEVT = "LOGEVT"; public static String PROFILER = "PROFILER"; public static String PAUSED_TRANSACTION = ":paused_transaction"; public Context() { super(); } /** * puts an Object in the transient Map */ public void put(Object key, Object value) { if (trace) { getProfiler().checkPoint( String.format(" %s='%s' [%s]", key, value, Thread.currentThread().getStackTrace()[2])); } getMap().put(key, value); synchronized (this) { notifyAll(); } } /** * puts an Object in the transient Map */ public void put(Object key, Object value, boolean persist) { if (trace) { getProfiler().checkPoint( String.format("P: %s='%s' [%s]", key, value, new Throwable().getStackTrace()[1].toString())); } if (persist && value instanceof Serializable) getPMap().put(key, value); getMap().put(key, value); } /** * Get */ public Object get(Object key) { return getMap().get(key); } public Object get(Object key, Object defValue) { Object obj = getMap().get(key); return obj != null ? obj : defValue; } /** * Transient remove */ public synchronized Object remove(Object key) { getPMap().remove(key); return getMap().remove(key); } public String getString(Object key) { return (String) getMap().get(key); } public String getString(Object key, Object defValue) { return (String) get(key, defValue); } public void dump(PrintStream p, String indent) { String inner = indent + " "; p.println(indent + "<context>"); dumpMap(p, inner); p.println(indent + "</context>"); } /** * persistent get with timeout * @param key the key * @param timeout timeout * @return object (null on timeout) */ public synchronized Object get(Object key, long timeout) { Object obj; long now = System.currentTimeMillis(); long end = now + timeout; while ((obj = map.get(key)) == null && (now = System.currentTimeMillis()) < end) { try { this.wait(end - now); } catch (InterruptedException e) { } } return obj; } public void writeExternal(ObjectOutput out) throws IOException { out.writeByte(0); // reserved for future expansion (version id) Set s = getPMap().entrySet(); out.writeInt(s.size()); Iterator iter = s.iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); out.writeObject(entry.getKey()); out.writeObject(entry.getValue()); } } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { in.readByte(); // ignore version for now getMap(); // force creation of map getPMap(); // and pmap int size = in.readInt(); for (int i = 0; i < size; i++) { String k = (String) in.readObject(); Object v = in.readObject(); map.put(k, v); pmap.put(k, v); } } /** * @return persistent map */ private synchronized Map getPMap() { if (pmap == null) pmap = Collections.synchronizedMap(new LinkedHashMap()); return pmap; } /** * @return transient map */ public synchronized Map getMap() { if (map == null) map = Collections.synchronizedMap(new LinkedHashMap()); return map; } protected void dumpMap(PrintStream p, String indent) { if (map == null) return; for (Map.Entry<String, Object> entry : map.entrySet()) { dumpEntry(p, indent, entry); } } protected void dumpEntry(PrintStream p, String indent, Map.Entry<String, Object> entry) { String key = entry.getKey(); if (key.startsWith(".") || key.startsWith("*")) return; // see jPOS-63 p.printf("%s%s%s: ", indent, key, pmap != null && pmap.containsKey(key) ? "(P)" : ""); Object value = entry.getValue(); if (value instanceof Loggeable) { p.println(""); ((Loggeable) value).dump(p, indent + " "); p.print(indent); } else if (value instanceof Element) { p.println(""); p.println(indent + "<![CDATA["); XMLOutputter out = new XMLOutputter(Format.getPrettyFormat()); out.getFormat().setLineSeparator(System.lineSeparator()); try { out.output((Element) value, p); } catch (IOException ex) { ex.printStackTrace(p); } p.println(""); p.println(indent + "]]>"); } else if (value instanceof byte[]) { byte[] b = (byte[]) value; p.println(""); p.println(ISOUtil.hexdump(b)); p.print(indent); } else if (value instanceof LogEvent) { ((LogEvent) value).dump(p, indent); p.print(indent); } else if (value != null) { try { p.print(ISOUtil.normalize(value.toString(), true)); } catch (Exception e) { p.println(e.getMessage()); p.print(indent); } } p.println(); } /** * return a LogEvent used to store trace information * about this transaction. * If there's no LogEvent there, it creates one. * @return LogEvent */ synchronized public LogEvent getLogEvent() { LogEvent evt = (LogEvent) get(LOGEVT); if (evt == null) { evt = new LogEvent(); evt.setNoArmor(true); put(LOGEVT, evt); } return evt; } /** * return (or creates) a Profiler object * @return Profiler object */ synchronized public Profiler getProfiler() { Profiler prof = (Profiler) get(PROFILER); if (prof == null) { prof = new Profiler(); put(PROFILER, prof); } return prof; } /** * adds a trace message * @param msg trace information */ public void log(Object msg) { getLogEvent().addMessage(msg); } /** * add a checkpoint to the profiler */ public void checkPoint(String detail) { getProfiler().checkPoint(detail); } public void setPausedTransaction(PausedTransaction p) { put(PAUSED_TRANSACTION, p); synchronized (this) { if (resumeOnPause) { resume(); } } } public PausedTransaction getPausedTransaction() { return (PausedTransaction) get(PAUSED_TRANSACTION); } public void setTimeout(long timeout) { this.timeout = timeout; } public long getTimeout() { return timeout; } public synchronized void resume() { PausedTransaction pt = getPausedTransaction(); if (pt != null && !pt.isResumed()) { pt.setResumed(true); pt.getTransactionManager().push(this); } else { resumeOnPause = true; } } public boolean isTrace() { return trace; } public void setTrace(boolean trace) { if (trace) getProfiler(); this.trace = trace; } static final long serialVersionUID = 6056487212221438338L; }