/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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.1 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.narayana.osgi.jta.internal;
import com.arjuna.ats.arjuna.common.Uid;
import com.arjuna.ats.arjuna.exceptions.ObjectStoreException;
import com.arjuna.ats.arjuna.objectstore.ObjectStoreIterator;
import com.arjuna.ats.arjuna.objectstore.StoreManager;
import com.arjuna.ats.arjuna.state.InputObjectState;
import com.arjuna.ats.arjuna.tools.log.TransactionTypeManager;
import com.arjuna.ats.arjuna.tools.osb.mbean.ObjStoreBrowser;
import com.arjuna.ats.arjuna.tools.osb.util.JMXServer;
import com.arjuna.ats.internal.arjuna.tools.log.EditableTransaction;
import org.jboss.narayana.osgi.jta.ObjStoreBrowserService;
import javax.management.AttributeList;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:zfeng@redhat.com">Amos Feng</a>
*/
public class ObjStoreBrowserImpl implements ObjStoreBrowserService{
private ObjStoreBrowser osb;
private PrintStream printStream;
private List<String> recordTypes = new ArrayList<String>();
private String currentType = null;
private String currentLog = "";
private boolean attached = false;
public ObjStoreBrowserImpl(ObjStoreBrowser osb) {
try {
printStream = new PrintStream(System.out, true, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
System.err.println("Encoding " + StandardCharsets.UTF_8.name() + " is not supported");
throw new IllegalStateException(StandardCharsets.UTF_8.name() + " is not supported");
}
this.osb = osb;
}
@Override
public void probe() throws MBeanException {
osb.probe();
}
@Override
public List<String> types() {
recordTypes.clear();
InputObjectState types = new InputObjectState();
try {
if (StoreManager.getRecoveryStore().allTypes(types)) {
String typeName;
do {
try {
typeName = types.unpackString();
if (!recordTypes.contains(typeName))
recordTypes.add(typeName);
} catch (IOException e) {
typeName = "";
}
} while (typeName.length() != 0);
}
} catch (ObjectStoreException e) {
System.out.println(e);
}
return recordTypes;
}
@Override
public boolean select(String itype) {
if (attached) {
attached = false;
}
if (recordTypes.size() == 0) {
types();
}
if (!recordTypes.contains(itype)) {
printStream.printf("%s is not a valid transaction type%n", itype);
return false;
} else {
currentType = itype;
return true;
}
}
@Override
public void list(String itype) {
MBeanServer mbs = JMXServer.getAgent().getServer();
Set<ObjectInstance> transactions;
String osMBeanName = "jboss.jta:type=ObjectStore";
if (itype != null) {
if (select(itype) == false) return;
osMBeanName += ",itype=" + itype;
} else if (currentType != null) {
osMBeanName += ",itype=" + currentType;
} else {
printStream.printf("No type selected%n");
return;
}
try {
transactions = mbs.queryMBeans(new ObjectName(osMBeanName + ",*"), null);
} catch (Exception e) {
System.out.println(e);
return;
}
for (ObjectInstance oi : transactions) {
String transactionId = oi.getObjectName().getCanonicalName();
if (!transactionId.contains("puid") && transactionId.contains("itype")) {
printStream.printf("Transaction: %s%n", oi.getObjectName());
printStream.printf("-----------------------------------%n");
String participantQuery = transactionId + ",puid=*";
try {
Set<ObjectInstance> participants = mbs.queryMBeans(new ObjectName(participantQuery), null);
printAtrributes(printStream, "\t", mbs, oi);
printStream.printf("\tParticipants:%n");
for (ObjectInstance poi : participants) {
printStream.printf("\t\tParticipant: %s%n", poi);
printAtrributes(printStream, "\t\t\t", mbs, poi);
}
} catch (Exception e){
}
printStream.printf("%n");
}
}
}
private void printAtrributes(PrintStream printStream, String printPrefix, MBeanServer mbs, ObjectInstance oi)
throws IntrospectionException, InstanceNotFoundException, ReflectionException {
MBeanInfo info = mbs.getMBeanInfo( oi.getObjectName() );
MBeanAttributeInfo[] attributeArray = info.getAttributes();
int i = 0;
String[] attributeNames = new String[attributeArray.length];
for (MBeanAttributeInfo ai : attributeArray)
attributeNames[i++] = ai.getName();
AttributeList attributes = mbs.getAttributes(oi.getObjectName(), attributeNames);
for (javax.management.Attribute attribute : attributes.asList()) {
Object value = attribute.getValue();
String v = value == null ? "null" : value.toString();
printStream.printf("%s%s=%s%n", printPrefix, attribute.getName(), v);
}
}
@Override
public void attach(String id) {
if (attached)
System.err.println("Already attached.");
else {
try {
if (supportedLog(id)) {
currentLog = id;
attached = true;
} else {
System.err.println("can not attach to id " + id + " with type /" + currentType);
}
} catch (Exception e) {
System.err.println(e);
e.printStackTrace();
}
}
}
@Override
public void detach() {
if (!attached)
System.err.println("Not attached.");
currentLog = "";
attached = false;
}
@Override
public void forget(int idx) {
if (!attached) {
System.err.println("Not attached.");
} else if (!currentType.contains("AtomicAction")) {
System.err.println("Can not support this type");
} else {
Uid uid = new Uid(currentLog);
EditableTransaction act = TransactionTypeManager.getInstance().getTransaction("AtomicAction", uid);
try {
act.moveHeuristicToPrepared(idx);
} catch (IndexOutOfBoundsException ex) {
System.err.println("Invalid index.");
}
}
}
@Override
public void delete(int idx) {
if (!attached) {
System.err.println("Not attached.");
} else if (!currentType.contains("AtomicAction")) {
System.err.println("Can not support this type");
} else {
Uid uid = new Uid(currentLog);
EditableTransaction act = TransactionTypeManager.getInstance().getTransaction("AtomicAction", uid);
try {
act.deleteHeuristicParticipant(idx);
} catch (IndexOutOfBoundsException ex) {
System.err.println("Invalid index.");
}
}
}
private final boolean supportedLog (String logID) throws ObjectStoreException, IOException {
Uid id = new Uid(logID);
if (id.equals(Uid.nullUid())) {
System.err.println(logID + " is null Uid");
} else if (currentType == null) {
printStream.printf("No type selected%n");
} else if (!currentType.contains("AtomicAction")) {
printStream.printf("Can not support this type");
} else {
ObjectStoreIterator iter = new ObjectStoreIterator(StoreManager.getRecoveryStore(), "/" + currentType);
Uid u;
do {
u = iter.iterate();
if (u.equals(id))
return true;
} while (Uid.nullUid().notEquals(u));
}
return false;
}
@Override
public void start() {
osb.start();
}
@Override
public void stop() {
osb.stop();
}
}