/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt 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.profiler.memoryprofiler.engine;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;
import org.jboss.profiler.memoryprofiler.model.MemoryClass;
import org.jboss.profiler.memoryprofiler.model.MemoryObject;
import org.jboss.profiler.memoryprofiler.model.MemoryReference;
import org.jboss.profiler.memoryprofiler.model.MemoryReferenceSummary;
import org.jboss.profiler.memoryprofiler.model.ReferenceContainer;
/**
* Controls the iterations between objects.
* We don't want to relly on the POJO model as it can be converted in binary files eventually.
* So, every relationship operation, and accessing operation will be done through this controller
*
* Basically the rule is.. Do not use any relationships between POJOs, always use this controller to solve it as they will be in files in a near future.
*
* @author Clebert Suconic
*/
public class MemorySnapshotController {
MemorySnapshotEngine engine;
MemorySnapshoDAO dao;
public MemorySnapshotController(MemorySnapshotEngine engine){
this.engine=engine;
dao = new MemorySnapshoDAO(engine);
}
static class ClassComparator implements Comparator
{
boolean sortOnBytes;
public ClassComparator(boolean sortOnBytes)
{
this.sortOnBytes=sortOnBytes;
}
public int compare(Object left, Object right)
{
if (sortOnBytes)
{
long value = ((MemoryClass)left).getLoadedSize() - ((MemoryClass)right).getLoadedSize();
if (value>0)
{
return -1;
}
else if (value<1)
{
return 1;
}
}
/// else else...
int signatureCompare = ((MemoryClass)left).getSignature().compareTo(((MemoryClass)right).getSignature());
if (signatureCompare==0)
{
long value =((MemoryClass)left).getId()-((MemoryClass)right).getId();
if (value>0) return 1;
else if (value<1) return -1;
else return 0;
} else {
return signatureCompare;
}
}
}
public Collection filterRoots(boolean sortOnBytes) throws Exception
{
Collection memoryClasses = dao.selectRoots();
TreeSet set = new TreeSet(new ClassComparator(sortOnBytes));
set.addAll(memoryClasses);
return set;
}
public Collection filterRoots(int type, boolean sortOnBytes) throws Exception
{
Collection memoryClasses = dao.selectRoots();
TreeSet set = new TreeSet(new ClassComparator(sortOnBytes));
Iterator iter = memoryClasses.iterator();
while (iter.hasNext())
{
MemoryClass clazz = (MemoryClass) iter.next();
if (clazz.getClassType()==type)
{
set.add(clazz);
}
}
return set;
}
private long parseObjectId(String pathInstance) throws Exception
{
return Long.parseLong(pathInstance.substring(1));
}
public Collection getObjects(MemoryClass clazz) throws Exception
{
return dao.selectObjects(clazz);
}
public MemoryClass findClass(long classId) throws Exception
{
return dao.selectClass(classId);
}
public MemoryObject findObject(long objectId) throws Exception
{
return dao.selectObject(objectId);
}
/** Solve all the references on a path.
* @parameter forward if true will use indexedReferencesByReferencer, or indexedReferencesByReferenced if false
* @path an array of the path to the reference. It's always the ID used in the objects. Use C<ObjectID> for classes and O<ObjectID> for objects. Remember that a Class is also an object but you might want to find references to the object class.
*
* The basic difference on using Classes or Objects in the path is that when we use a Class we will look for all instances of a class in a cluster.
* */
public Collection summarizeReferenceByPath(boolean forward,String [] path) throws Exception
{
ArrayList currentList = new ArrayList();
HashMap summariesByClass = new HashMap();
for (int i=0;i<path.length;i++)
{
if (i==0)
{
if (path[i].startsWith("C"))
{
long classId = parseObjectId(path[0]);
MemoryClass clazz = findClass(classId);
currentList.addAll(getObjects(clazz));
} else {
long objectId = parseObjectId(path[0]);
MemoryObject objectFound = findObject(objectId);
currentList.add(objectFound);
}
} else {
if (path[i].startsWith("C"))
{
long classId = parseObjectId(path[i]);
MemoryClass clazz = findClass(classId);
MemoryReferenceSummary summary = (MemoryReferenceSummary)summariesByClass.get(clazz);
currentList.clear();
if (summary!=null)
{
currentList.addAll(summary.getObjectsReferenced().values());
}
} else {
long objectId = parseObjectId(path[i]);
MemoryObject objectFound = findObject(objectId);
MemoryClass clazz = objectFound.getMemoryClass();
MemoryReferenceSummary summary = (MemoryReferenceSummary)summariesByClass.get(clazz);
if (summary!=null)
{
// We could look for the object at summary.getObjectsReferenced()... but we would get the same result... so, just don't bother about it.
currentList.add(objectFound);
}
}
summariesByClass.clear();
}
int count=0;
Iterator iter = currentList.iterator();
while (iter.hasNext())
{
if ((count++)%100==0)
{
System.out.println("Treated " + count + " references");
}
MemoryObject objectReference = (MemoryObject)iter.next();
ReferenceContainer container = this.dao.selectReferences(objectReference,forward);
if (container==null)
{
continue;
}
Iterator referencesToIterator = container.getListOfReferences().iterator();
while (referencesToIterator.hasNext())
{
MemoryReference reference = (MemoryReference) referencesToIterator.next();
MemoryObject objectReferenceTo = null;
objectReferenceTo=reference.getObjectReferred();
MemoryClass memoryClazz = this.solveClassReference(objectReferenceTo);
if (memoryClazz==null)
{
long classId=0;
if (objectReferenceTo!=null)
{
classId=objectReferenceTo.getClassId();
}
System.out.println("Didn't find class for " + classId + " Reference = (" + reference.toString()+ ")");
}
MemoryReferenceSummary summary = (MemoryReferenceSummary)summariesByClass.get(memoryClazz);
if (summary==null)
{
summary = new MemoryReferenceSummary();
summary.setReferenceTo(memoryClazz);
summariesByClass.put(memoryClazz,summary);
}
if (summary.getObjectsReferenced().get(objectReferenceTo)==null) {
summary.getObjectsReferenced().put(objectReferenceTo,objectReferenceTo);
summary.setNumberOfDistinctObjects(summary.getNumberOfDistinctObjects()+1);
}
summary.setNumberOfReferences(summary.getNumberOfReferences()+1);
if (reference.isThreadReference())
{
summary.setNumberOfThreadReferences(summary.getNumberOfThreadReferences()+1);
}
}
}
}
return summariesByClass.values();
}
public MemoryObject solveClassLoaderReference(MemoryClass clazz) throws Exception
{
return dao.selectObject(clazz.getClassLoaderId());
}
public MemoryClass solveClassReference (MemoryObject mobject) throws Exception
{
if (mobject==null)
{
return null;
} else
{
return dao.selectClass(mobject.getClassId());
}
}
public MemoryObject solveObject (long objectId) throws Exception
{
return dao.selectObject(objectId);
}
public Collection solveLoadedClass(long classLoaderId,boolean sortOnBytes) throws Exception
{
TreeSet set = new TreeSet(new ClassComparator(sortOnBytes));
set.addAll(dao.selectRoots(classLoaderId));
return set;
}
}