/** * Licensed to Cloudera, Inc. under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. Cloudera, Inc. licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cloudera.flume.master.logical; import static com.cloudera.flume.conf.PatternMatch.kind; import static com.cloudera.flume.conf.PatternMatch.recursive; import static com.cloudera.flume.conf.PatternMatch.var; import java.io.IOException; import java.util.Map; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.tree.CommonTree; import org.apache.commons.lang.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cloudera.flume.conf.FlumeBuilder; import com.cloudera.flume.conf.FlumePatterns; import com.cloudera.flume.conf.FlumeSpecException; import com.cloudera.flume.conf.FlumeSpecGen; import com.cloudera.flume.conf.PatternMatch; import com.cloudera.flume.master.ConfigurationManager; import com.cloudera.flume.master.StatusManager; import com.cloudera.flume.master.TranslatingConfigurationManager; import com.cloudera.flume.master.Translator; import com.cloudera.flume.master.logical.LogicalNameManager.PhysicalNodeInfo; /** * This configuration manager translates users specified logical configurations * into physical configurations. */ public class LogicalConfigurationManager extends TranslatingConfigurationManager implements Translator { static final Logger LOG = LoggerFactory.getLogger(LogicalConfigurationManager.class); public static final String NAME = "LogicalTranslator"; final LogicalNameManager nameMan; /** * Construct a LogicalConfigurationManager with specified parent, self and * StatusManagers. */ public LogicalConfigurationManager(ConfigurationManager parent, ConfigurationManager self, StatusManager statman) { super(parent, self); this.nameMan = new LogicalNameManager(parent, statman); } /** * This method takes a logical sink and returns an AST of its physical sink * representation. **/ CommonTree substLogicalSink(String sink) throws RecognitionException, FlumeSpecException { CommonTree lsnkTree = FlumeBuilder.parseSink(sink); LOG.debug(lsnkTree.toStringTree()); PatternMatch p = recursive(var("lsnk", kind("SINK").child( kind("logicalSink")))); Map<String, CommonTree> matches = p.match(lsnkTree); if (matches == null) { // do nothing, return lsnkTree; } CommonTree lsnk = matches.get("lsnk"); final String orig = StringEscapeUtils.escapeJava(FlumeSpecGen .genEventSink(lsnk)); String tgtLn = FlumeBuilder.buildArg((CommonTree) lsnk.getChild(1)); PhysicalNodeInfo pni = nameMan.getPhysicalNodeInfo(tgtLn); String tgtPhysNode = getPhysicalNode(tgtLn); if (tgtPhysNode == null || pni == null) { // force a translation to an valid but incomplete translation pni = new PhysicalNodeInfo() { @Override public String getPhysicalSink() { return "fail( \"" + orig + "\" )"; } @Override public String getPhysicalSource() { return "fail"; } }; } String snk = pni.getPhysicalSink(); if (snk == null) { // bail out return null; } CommonTree psnkTree = FlumeBuilder.parseSink(snk); PatternMatch.replaceChildren(lsnk, psnkTree); return lsnkTree; } /** * This method gets a logical node 'ln' and a logicalSource 'source', and * substitutes in a physical source. */ CommonTree substLogicalSource(String ln, String source) throws RecognitionException { CommonTree lsrcTree = FlumeBuilder.parseSource(source); LOG.debug(lsrcTree.toStringTree()); PatternMatch p = FlumePatterns.source("logicalSource"); Map<String, CommonTree> matches = p.match(lsrcTree); if (matches == null) { // if was previously a logical source, unregister it. nameMan.setPhysicalNode(ln, null); // do nothing, return lsrcTree; } // check logical name manager PhysicalNodeInfo pni = nameMan.getPhysicalNodeInfo(ln); if (pni == null) { // bail out nameMan.updateNode(ln); pni = nameMan.getPhysicalNodeInfo(ln); if (pni == null) { // return failure. return null; } } String src = pni.getPhysicalSource(); String phys = getPhysicalNode(ln); if (phys == null) { src = "fail( \"no physical translation for " + ln + "\" )"; } if (src == null) { LOG.warn("Physical Source for " + ln + " not translated"); return null; } CommonTree psrcTree = FlumeBuilder.parseSource(src); PatternMatch.replaceChildren(lsrcTree, psrcTree); return lsrcTree; } /** * Translates a logical source into a physical source */ public String translateSource(String logicalnode, String source) throws FlumeSpecException { try { CommonTree pCt = substLogicalSource(logicalnode, source); if (pCt == null) { return source; } String pStr = FlumeSpecGen.genEventSource(pCt); return pStr; } catch (RecognitionException e) { LOG.error("Problem with physical sink", e); } return null; } /** * Translates a logical sink into a physical sink */ public String translateSink(String logicalnode, String sink) throws FlumeSpecException { try { String cur = sink; String last = null; while (!cur.equals(last)) { CommonTree pCt = substLogicalSink(cur); if (pCt == null) { return cur; } last = cur; cur = FlumeSpecGen.genEventSink(pCt); } return cur; } catch (RecognitionException e) { LOG.error("Problem with physical sink", e); } return null; } /** * {@inheritDoc} */ @Override public void refreshAll() throws IOException { try { nameMan.update(); } catch (RecognitionException e) { LOG.error("Internal Error: " + e.getLocalizedMessage(), e); throw new IOException("Internal Error: " + e.getMessage()); } super.refreshAll(); } /** * {@inheritDoc} */ @Override public void updateAll() throws IOException { try { nameMan.update(); } catch (RecognitionException e) { LOG.error("Internal Error: " + e.getLocalizedMessage(), e); throw new IOException("Internal Error: " + e.getMessage()); } super.updateAll(); } /** * {@inheritDoc} */ @Override public String getName() { return NAME; } }