/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat, Inc. and/or its affiliates, * and individual contributors as indicated by the @author tags. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * 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, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * (C) 2010, * @author JBoss, by Red Hat. */ package com.arjuna.ats.internal.arjuna.objectstore.hornetq; import java.io.IOException; import java.io.SyncFailedException; import java.util.HashSet; import java.util.Set; import com.arjuna.ats.arjuna.common.Uid; import com.arjuna.ats.arjuna.exceptions.ObjectStoreException; import com.arjuna.ats.arjuna.logging.tsLogger; import com.arjuna.ats.arjuna.objectstore.ObjectStoreAPI; import com.arjuna.ats.arjuna.objectstore.StateStatus; import com.arjuna.ats.arjuna.state.InputObjectState; import com.arjuna.ats.arjuna.state.OutputObjectState; import com.arjuna.ats.internal.arjuna.common.UidHelper; import com.arjuna.common.internal.util.propertyservice.BeanPopulator; /* transaction-jboss-beans.xml: <bean name="HornetqJournalEnvironmentBean" class="com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqJournalEnvironmentBean"> <property name="storeDir">${jboss.server.data.dir}/tx-object-store/HornetqJournalStore</property> </bean> <bean name="HornetqJournalStore" class="com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqJournalStore"> <constructor> <parameter><inject bean="HornetqJournalEnvironmentBean"/></parameter> </constructor> </bean> <bean name="HornetqObjectStoreAdaptor" class="com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqObjectStoreAdaptor"> <constructor> <parameter><inject bean="HornetqJournalStore"/></parameter> </constructor> </bean> <bean name="TxStoreManager" class="com.arjuna.ats.arjuna.objectstore.StoreManager"> <constructor> <parameter><inject bean="HornetqObjectStoreAdaptor"/></parameter> <parameter><null/></parameter> </constructor> </bean> plus RecMgr/TxMgr lifecycle deps */ /** * Adaptor class that wraps the store to make it look like an ObjectStore. * * @author Jonathan Halliday (jonathan.halliday@redhat.com), 2010-03 */ public class HornetqObjectStoreAdaptor implements ObjectStoreAPI { private final HornetqJournalStore store; // used for standalone bootstrap via StoreManager public HornetqObjectStoreAdaptor() throws IOException { HornetqJournalEnvironmentBean envBean = BeanPopulator.getDefaultInstance(HornetqJournalEnvironmentBean.class); this.store = new HornetqJournalStore(envBean); } // used for beans wiring type bootstrap when running embedded. public HornetqObjectStoreAdaptor(HornetqJournalStore store) { this.store = store; } @Override public void start() { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.start()"); } try { store.start(); } catch(Exception e) { throw new RuntimeException(e); } } @Override public void stop() { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.stop()"); } try { store.stop(); } catch(Exception e) { throw new RuntimeException(e); } } /** * Read the object's shadowed state. * * @param u The object to work on. * @param tn The type of the object to work on. * @return the state of the object. */ @Override public InputObjectState read_uncommitted(Uid u, String tn) throws ObjectStoreException { throw new ObjectStoreException(tsLogger.i18NLogger.get_method_not_implemented()); } /** * Remove the object's uncommitted state. * * @param u The object to work on. * @param tn The type of the object to work on. * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean remove_uncommitted(Uid u, String tn) throws ObjectStoreException { throw new ObjectStoreException(tsLogger.i18NLogger.get_method_not_implemented()); } private String ensureTypenamePrefix(String typeName) { if(!typeName.startsWith("/")) { typeName = "/"+typeName; } return typeName; } /** * Read the object's committed state. * * @param u The object to work on. * @param typeName The type of the object to work on. * @return the state of the object. */ @Override public InputObjectState read_committed(Uid u, String typeName) throws ObjectStoreException { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.read_committed("+u+", "+typeName+")"); } typeName = ensureTypenamePrefix(typeName); return store.read_committed(u, typeName); } /** * Remove the object's committed state. * * @param u The object to work on. * @param typeName The type of the object to work on. * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean remove_committed(Uid u, String typeName) throws ObjectStoreException { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.remove_committed("+u+", "+typeName+")"); } typeName = ensureTypenamePrefix(typeName); return store.remove_committed(u, typeName); } /** * Hide the object's state in the object store. Used by crash * recovery. * * @param u The object to work on. * @param tn The type of the object to work on. * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean hide_state(Uid u, String tn) throws ObjectStoreException { throw new ObjectStoreException(tsLogger.i18NLogger.get_method_not_implemented()); } /** * Reveal a hidden object's state. * * @param u The object to work on. * @param tn The type of the object to work on. * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean reveal_state(Uid u, String tn) throws ObjectStoreException { throw new ObjectStoreException(tsLogger.i18NLogger.get_method_not_implemented()); } /** * Commit the object's state in the object store. * * @param u The object to work on. * @param tn The type of the object to work on. * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean commit_state(Uid u, String tn) throws ObjectStoreException { throw new ObjectStoreException(tsLogger.i18NLogger.get_method_not_implemented()); } /** * @param u The object to query. * @param typeName The type of the object to query. * @return the current state of the object's state (e.g., shadowed, * committed ...) [StateStatus] */ @Override public int currentState(Uid u, String typeName) throws ObjectStoreException { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.currentState("+u+", "+typeName+")"); } typeName = ensureTypenamePrefix(typeName); if( store.contains(u, typeName)) { return StateStatus.OS_COMMITTED; } else { return StateStatus.OS_UNKNOWN; } } /** * Write a copy of the object's uncommitted state. * * @param u The object to work on. * @param tn The type of the object to work on. * @param buff The state to write. * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean write_uncommitted(Uid u, String tn, OutputObjectState buff) throws ObjectStoreException { throw new ObjectStoreException(tsLogger.i18NLogger.get_method_not_implemented()); } /** * Write a new copy of the object's committed state. * * @param u The object to work on. * @param typeName The type of the object to work on. * @param buff The state to write. * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean write_committed(Uid u, String typeName, OutputObjectState buff) throws ObjectStoreException { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.write_committed("+u+", "+typeName+")"); } typeName = ensureTypenamePrefix(typeName); return store.write_committed(u, typeName, buff); } @Override public boolean allObjUids(String typeName, InputObjectState foundInstances) throws ObjectStoreException { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.allObjUids("+typeName+")"); } typeName = ensureTypenamePrefix(typeName); return allObjUids(typeName, foundInstances, StateStatus.OS_UNKNOWN); } /** * Obtain all of the Uids for a specified type. * * @param typeName The type to scan for. * @param foundInstances The object state in which to store the Uids * @param matchState The file type to look for (e.g., committed, shadowed). [StateStatus] * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean allObjUids(String typeName, InputObjectState foundInstances, int matchState) throws ObjectStoreException { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.allObjUids("+typeName+", "+matchState+")"); } boolean result = true; typeName = ensureTypenamePrefix(typeName); Uid[] uids = store.getUidsForType(typeName); // may contain trailing null elements OutputObjectState buffer = new OutputObjectState(); try { if(uids != null && (matchState == StateStatus.OS_UNKNOWN || matchState == StateStatus.OS_COMMITTED)) { for (Uid uid: uids) { if(uid != null) { UidHelper.packInto(uid, buffer); } } } UidHelper.packInto(Uid.nullUid(), buffer); } catch (IOException e) { throw new ObjectStoreException(e); } foundInstances.setBuffer(buffer.buffer()); return result; } /** * Obtain all types of objects stored in the object store. * * @param foundTypes The state in which to store the types. * @return <code>true</code> if no errors occurred, <code>false</code> * otherwise. */ @Override public boolean allTypes(InputObjectState foundTypes) throws ObjectStoreException { if(tsLogger.logger.isTraceEnabled()) { tsLogger.logger.trace("HornetqObjectStore.allTypes()"); } boolean result = true; String[] knownTypes = store.getKnownTypes(); // may contain trailing null elements Set<String> typeSet = new HashSet<String>(); if (knownTypes == null || knownTypes.length == 0) return true; OutputObjectState buffer = new OutputObjectState(); try { for (String typeName: knownTypes) { if(typeName == null) { continue; } if(typeName.startsWith("/")) { typeName = typeName.substring(1); } if(typeName.contains("/")) { String value = ""; String[] parents = typeName.split("/"); for(String parent : parents) { if(parent.length() == 0) { continue; } if(value.length() > 0) { value = value+"/"; } value = value+parent; if(!typeSet.contains(value)) { typeSet.add(value); buffer.packString(value); } } } else { buffer.packString(typeName); } } buffer.packString(""); } catch (IOException e) { throw new ObjectStoreException(e); } foundTypes.setBuffer(buffer.buffer()); return result; } /** * Some object store implementations may be running with automatic * sync disabled. Calling this method will ensure that any states are * flushed to disk. */ @Override public void sync() throws SyncFailedException, ObjectStoreException { // null-op in this impl. } /** * @return the "name" of the object store. Where in the hierarchy it appears, e.g., /ObjectStore/MyName/... */ @Override public String getStoreName() { return store.getStoreName(); } @Override public boolean fullCommitNeeded() { return false; } /** * Is the current state of the object the same as that provided as the last * parameter? * * @param u The object to work on. * @param tn The type of the object. * @param st The expected type of the object. [StateType] * @return <code>true</code> if the current state is as expected, * <code>false</code> otherwise. */ @Override public boolean isType(Uid u, String tn, int st) throws ObjectStoreException { return false; } }