/* * JBoss, Home of Professional Open Source * Copyright 2009 Red Hat Inc. and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * 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.infinispan.tree; import org.infinispan.AdvancedCache; import org.infinispan.atomic.AtomicMap; import org.infinispan.atomic.AtomicMapLookup; import org.infinispan.batch.AutoBatchSupport; import org.infinispan.batch.BatchContainer; import org.infinispan.util.concurrent.locks.LockManager; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; public class TreeStructureSupport extends AutoBatchSupport { private static final Log log = LogFactory.getLog(TreeStructureSupport.class); protected final AdvancedCache<NodeKey, AtomicMap<?, ?>> cache; protected final TreeContextContainer tcc = new TreeContextContainer(); @SuppressWarnings("unchecked") public TreeStructureSupport(AdvancedCache<?, ?> cache, BatchContainer batchContainer) { this.cache = (AdvancedCache<NodeKey, AtomicMap<?, ?>>) CacheAdapter.createAdapter(cache, tcc); this.batchContainer = batchContainer; } public boolean exists(Fqn f) { startAtomic(); try { return cache.containsKey(new NodeKey(f, NodeKey.Type.DATA)) && cache.containsKey(new NodeKey(f, NodeKey.Type.STRUCTURE)); } finally { endAtomic(); } } /** * @param fqn * @return true if created, false if this was not necessary */ boolean createNodeInCache(Fqn fqn) { startAtomic(); try { NodeKey dataKey = new NodeKey(fqn, NodeKey.Type.DATA); NodeKey structureKey = new NodeKey(fqn, NodeKey.Type.STRUCTURE); if (cache.containsKey(dataKey) && cache.containsKey(structureKey)) return false; Fqn parent = fqn.getParent(); if (!fqn.isRoot()) { if (!exists(parent)) createNodeInCache(parent); AtomicMap<Object, Fqn> parentStructure = getStructure(parent); parentStructure.put(fqn.getLastElement(), fqn); } getAtomicMap(structureKey); getAtomicMap(dataKey); if (log.isTraceEnabled()) log.tracef("Created node %s", fqn); return true; } finally { endAtomic(); } } AtomicMap<Object, Fqn> getStructure(Fqn fqn) { return getAtomicMap(new NodeKey(fqn, NodeKey.Type.STRUCTURE)); } public static boolean isLocked(LockManager lockManager, Fqn fqn) { return ((lockManager.isLocked(new NodeKey(fqn, NodeKey.Type.STRUCTURE)) && lockManager.isLocked(new NodeKey(fqn, NodeKey.Type.DATA)))); } /** * Visual representation of a tree * * @param cache cache to dump * @return String rep */ public static String printTree(TreeCache<?, ?> cache, boolean details) { StringBuilder sb = new StringBuilder(); sb.append("\n\n"); // walk tree sb.append("+ ").append(Fqn.SEPARATOR); if (details) sb.append(" ").append(cache.getRoot().getData()); sb.append("\n"); addChildren(cache.getRoot(), 1, sb, details); return sb.toString(); } private static void addChildren(Node<?, ?> node, int depth, StringBuilder sb, boolean details) { for (Node<?, ?> child : node.getChildren()) { for (int i = 0; i < depth; i++) sb.append(" "); // indentations sb.append("+ "); sb.append(child.getFqn().getLastElementAsString()).append(Fqn.SEPARATOR); if (details) sb.append(" ").append(child.getData()); sb.append("\n"); addChildren(child, depth + 1, sb, details); } } protected final <K, V> AtomicMap<K, V> getAtomicMap(NodeKey key) { return AtomicMapLookup.getAtomicMap(cache, key, tcc); } }