/* * Copyright 2014-2015 JKOOL, LLC. * * Licensed 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.jkoolcloud.tnt4j.selector; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import com.jkoolcloud.tnt4j.config.ConfigException; import com.jkoolcloud.tnt4j.config.Configurable; import com.jkoolcloud.tnt4j.core.OpLevel; import com.jkoolcloud.tnt4j.repository.FileTokenRepository; import com.jkoolcloud.tnt4j.repository.TokenRepository; import com.jkoolcloud.tnt4j.sink.DefaultEventSinkFactory; import com.jkoolcloud.tnt4j.sink.EventSink; import com.jkoolcloud.tnt4j.utils.Utils; /** * <p> * {@link DefaultTrackingSelector} implements {@link TrackingSelector} interface and provides default file * based implementation for a tracking selector. Selector file should contain entries as follows: * * <code>key=SEV:value-regexp</code> Example (trace all severities, all orders): * <code>OrderApp.purchasing.order.id=DEBUG:.*</code> * * @see OpLevel * * @version $Revision: 7 $ * */ public class DefaultTrackingSelector implements TrackingSelector, Configurable { private static EventSink logger = DefaultEventSinkFactory.defaultEventSink(DefaultTrackingSelector.class); private static final boolean DEFAULT_RETURN_UNDEFINED = Boolean.valueOf(System.getProperty("tnt4j.selector.undefined.isset", "true")); private HashMap<Object, PropertyToken> tokenMap = new HashMap<Object, PropertyToken>(89); private Map<String, Object> config = null; private TokenRepository tokenRepository = null; private PropertyListenerImpl listener = null; /** * Create a default tracking selector. Each selector needs to be backed by a repository {@link TokenRepository} * . * */ public DefaultTrackingSelector() { } /** * Create a default tracking selector. Each selector needs to be backed by a repository {@link TokenRepository} * . * * @param repository * token repository implementation */ public DefaultTrackingSelector(TokenRepository repository) { setRepository(repository); } @Override public boolean isOpen() { return tokenRepository != null && tokenRepository.isOpen(); } @Override public synchronized void open() throws IOException { if (tokenRepository == null) { tokenRepository = new FileTokenRepository(); } if (isDefined()) { tokenRepository.open(); listener = new PropertyListenerImpl(this, logger); tokenRepository.addRepositoryListener(listener); reloadConfig(); } else { logger.log(OpLevel.DEBUG, "Undefined token repository={0}: default isSet()={1}", tokenRepository, DEFAULT_RETURN_UNDEFINED); } } @Override public synchronized void close() throws IOException { clear(); if (tokenRepository != null) { tokenRepository.removeRepositoryListener(listener); Utils.close(tokenRepository); } } protected void reloadConfig() { clear(); Iterator<? extends Object> keys = tokenRepository.getKeys(); if (keys == null) return; while (keys.hasNext()) { String key = String.valueOf(keys.next()); putKey(key, tokenRepository.get(key).toString()); } } protected void putKey(Object key, Object val) { String value = String.valueOf(val); int index = value.indexOf(":"); try { PropertyToken propertyToken = null; if (index > 0) { // token consists of sev:reg-exp pair String sevValue = value.substring(0, index); String valuePattern = value.substring(index + 1); OpLevel sevLimit = OpLevel.valueOf(sevValue.toUpperCase()); propertyToken = new PropertyToken(sevLimit, key, value, valuePattern); } else { // token only has severity limit specified String sevValue = value.trim(); if (!sevValue.isEmpty()) { OpLevel sevLimit = OpLevel.valueOf(sevValue.toUpperCase()); propertyToken = new PropertyToken(sevLimit, key, value, null); } } if (propertyToken != null) { logger.log(OpLevel.DEBUG, "putkey: repository={0}, token={1}", tokenRepository, propertyToken); tokenMap.put(key, propertyToken); } } catch (Throwable ex) { logger.log(OpLevel.ERROR, "Failed to process key={0}, value={1}, repository={2}", key, value, tokenRepository, ex); } } @Override public boolean isSet(OpLevel sev, Object key) { return isSet(sev, key, null); } @Override public boolean isSet(OpLevel sev, Object key, Object value) { if (!isDefined()) { return DEFAULT_RETURN_UNDEFINED; } PropertyToken token = tokenMap.get(key); return (token != null? token.isMatch(sev, key, value): false); } @Override public void remove(Object key) { tokenMap.remove(key); } @Override public Object get(Object key) { PropertyToken token = tokenMap.get(key); return token != null ? token.getValue() : null; } @Override public void set(OpLevel sev, Object key, Object value) { putKey(key, value != null ? sev.toString() + ":" + value : sev.toString()); } @Override public void set(OpLevel sev, Object key) { set(sev, key, null); } @Override public Iterator<? extends Object> getKeys() { return tokenRepository != null? tokenRepository.getKeys(): null; } @Override public TokenRepository getRepository() { return tokenRepository; } protected void clear() { tokenMap.clear(); } @Override public void setRepository(TokenRepository repo) { Utils.close(this); tokenRepository = repo; } @Override public Map<String, Object> getConfiguration() { return config; } @Override public void setConfiguration(Map<String, Object> props) throws ConfigException { config = props; TokenRepository tokenRepo = (TokenRepository) Utils.createConfigurableObject("Repository", "Repository.", config); setRepository(tokenRepo); } @Override public boolean exists(Object key) { return get(key) != null; } @Override public boolean isDefined() { return (tokenRepository != null && tokenRepository.isDefined()); } }