/* * RHQ Management Platform * Copyright (C) 2005-2009 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * 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 General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.plugins.apache.augeas; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import net.augeas.Augeas; import org.rhq.augeas.config.AugeasModuleConfig; import org.rhq.augeas.node.AugeasNode; import org.rhq.augeas.tree.AugeasTreeException; import org.rhq.augeas.tree.impl.AugeasTreeLazy; /** * For Apache, we need our own implementation of the tree * because we need to build the tree such that it transparently * handles the include directives (i.e. the call to {@link #match(String)} * or {@link #matchRelative(AugeasNode, String)} should return * nodes as if the Include directive was replaced by the contents * of the included file. * * @author Lukas Krejci * @author Filip Drabek */ public class ApacheAugeasTree extends AugeasTreeLazy { private Map<AugeasNode, List<String>> includes; private List<String> includeGlobs; public ApacheAugeasTree(String serverRootPath, Augeas ag, AugeasModuleConfig moduleConfig) { super(ag, moduleConfig); this.includeGlobs = initIncludeGlobs(serverRootPath); } protected AugeasNode instantiateNode(String fullPath) { return new ApacheAugeasNode(fullPath, this); } public Map<AugeasNode, List<String>> getIncludes() { return includes; } public void setIncludes(Map<AugeasNode, List<String>> includes) { this.includes = includes; } public List<AugeasNode> match(String expression) throws AugeasTreeException { if (!expression.startsWith(AUGEAS_DATA_PATH)) expression = AUGEAS_DATA_PATH + expression; /*AugeasNode node = null; int max = 0; for (AugeasNode nd : includes.keySet()) { for (String file : includes.get(nd)) { if (expression.startsWith(file)) { if (file.length() > max) { node = nd; max = file.length(); } } } } if (node == null){ node = rootNode; max = rootNode.getFullPath().length(); } return matchRelative(node, expression.substring(max + 1));*/ return matchInternal(expression); } public List<AugeasNode> matchRelative(AugeasNode node, String expression) throws AugeasTreeException { try { if (expression.indexOf(PATH_SEPARATOR) == 0) expression = expression.substring(1); return parseExpr(node, expression); } catch (Exception e) { throw new AugeasTreeException(e.getMessage()); } } @Override protected List<String> getIncludeGlobs() { return includeGlobs; } private int subExpressionIndex(String expr) { //we have to parse the expression carefully because of the //potential xpath qualifier that can contain path separators. //0 = normal //1 = in xpath qualifier //2 = in double-quoted string (inside the qualifier) //3 = in single-quoted string (inside the qualifier) int state = 0; int idx = 0; boolean found = false; while (!found && idx < expr.length()) { char currentChar = expr.charAt(idx); switch (state) { case 0: //normal switch (currentChar) { case '[': state = 1; break; case '/': found = true; break; } break; case 1: //xpath qualifier switch (currentChar) { case ']': state = 0; break; case '"': state = 2; break; case '\'': state = 3; break; } break; case 2: //double quoted string switch (currentChar) { case '"': state = 1; break; case '\\': idx++; break; } break; case 3: //single quoted string switch (currentChar) { case '\'': state = 1; break; case '\\': idx++; break; } break; } idx++; } return idx == expr.length() ? -1 : idx; } private List<AugeasNode> parseExpr(AugeasNode nd, String expr) throws Exception { int index = subExpressionIndex(expr); if (index == -1) return search(nd, expr); String subExpr = expr.substring(0, index - 1); List<AugeasNode> nodes = search(nd, subExpr); List<AugeasNode> nds = new ArrayList<AugeasNode>(); for (AugeasNode node : nodes) { List<AugeasNode> tempNodes = parseExpr(node, expr.substring(index)); if (tempNodes != null) nds.addAll(tempNodes); } return nds; } private List<AugeasNode> search(AugeasNode nd, String expr) throws Exception { String fullExpr = nd.getFullPath() + PATH_SEPARATOR + expr; List<AugeasNode> nodes = this.matchInternal(fullExpr); if (includes.containsKey(nd)) { List<String> files = includes.get(nd); for (String fileName : files) { List<AugeasNode> nds = this.matchInternal(fileName + PATH_SEPARATOR + expr); for (AugeasNode node : nds) { if (!nodes.contains(node)) nodes.add(node); } } } return nodes; } private List<AugeasNode> matchInternal(String expression) throws AugeasTreeException { if (!expression.startsWith(AUGEAS_DATA_PATH)) expression = AUGEAS_DATA_PATH + expression; List<String> res = getAugeas().match(expression); List<AugeasNode> nodes = new ArrayList<AugeasNode>(); for (String name : res) { nodes.add(getNode(name)); } return nodes; } /** * @param serverRootPath * @return */ private List<String> initIncludeGlobs(String serverRootPath) { ArrayList<String> ret = new ArrayList<String>(); for (String glob : getModuleConfig().getIncludedGlobs()) { File f = new File(glob); if (f.isAbsolute()) { ret.add(glob); } else { ret.add(new File(serverRootPath, glob).getPath()); } } return ret; } }