/*
* 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.source;
import java.util.Map;
import java.util.StringTokenizer;
import com.jkoolcloud.tnt4j.config.ConfigException;
import com.jkoolcloud.tnt4j.config.Configurable;
import com.jkoolcloud.tnt4j.locator.DefaultGeoService;
import com.jkoolcloud.tnt4j.locator.GeoLocator;
import com.jkoolcloud.tnt4j.utils.Utils;
/**
* This class provides default implementation of <code>SourceFactory</code> interface.
* New sources are created off the root source which is defined by <code>RootFQN</code>
* configuration property. This factory provides the following configuration attributes:
*
* <pre>
* {@code
* source.factory: com.jkoolcloud.tnt4j.source.SourceFactoryImpl
* source.factory.GEOADDR: New York
* source.factory.DATACENTER: MyDC
* source.factory.DEVICE: HPPRO
* source.factory.PROCESS: $java.process
* source.factory.RootFQN: PROCESS=?#RUNTIME=?#SERVER=?#NETADDR=?#DATACENTER=?#GEOADDR=?
* }
* </pre>
*
* @version $Revision: 1 $
*
*/
public class SourceFactoryImpl implements SourceFactory, Configurable {
public static final String UNKNOWN_SOURCE = "UNKNOWN";
public static final String DEFAULT_SOURCE_ROOT_SSN = System.getProperty("tnt4j.source.root.ssn", "tnt4j");
public static final String DEFAULT_SOURCE_ROOT_FQN = System.getProperty("tnt4j.source.root.fqname", "RUNTIME=?#SERVER=?#NETADDR=?#DATACENTER=?#GEOADDR=?");
private static final String TNT4J_SOURCE_PFIX = "tnt4j.source.";
private static final String USER_NAME_KEY = "user.name";
private static final String [] DEFAULT_SOURCES;
static {
int i = 0;
DEFAULT_SOURCES = new String[SourceType.length()];
String location = DefaultGeoService.getInstance().getCurrentCoords();
if (location != null) {
DEFAULT_SOURCES[SourceType.GEOADDR.ordinal()] = location;
}
for (SourceType type: SourceType.values()) {
String typeValue = UNKNOWN_SOURCE;
String typeString = type.toString().toUpperCase();
typeValue = System.getProperty(TNT4J_SOURCE_PFIX + typeString);
if (typeValue == null) {
if (typeString.equalsIgnoreCase(SourceType.SERVER.name())) {
typeValue = Utils.getLocalHostName();
} else if (typeString.equalsIgnoreCase(SourceType.RUNTIME.name())) {
typeValue = Utils.getVMName();
} else if (typeString.equalsIgnoreCase(SourceType.NETADDR.name())) {
typeValue = Utils.getLocalHostAddress();
} else if (typeString.equalsIgnoreCase(SourceType.USER.name())) {
typeValue = System.getProperty(USER_NAME_KEY);
} else {
typeValue = UNKNOWN_SOURCE;
}
}
if (typeValue.startsWith("$")) {
// points to another environment variable
typeValue = System.getProperty(typeValue.substring(1), UNKNOWN_SOURCE);
}
DEFAULT_SOURCES[i++] = typeValue;
}
}
private String rootFqn = DEFAULT_SOURCE_ROOT_FQN;
private String rootSSN = DEFAULT_SOURCE_ROOT_SSN;
private String [] defaultSources = DEFAULT_SOURCES.clone();
private Map<String, Object> config;
private Source rootSource;
private GeoLocator geoLocator = DefaultGeoService.getInstance();
public SourceFactoryImpl() {
rootSource = newFromFQN(rootFqn);
geoLocator = DefaultGeoService.getInstance();
}
@Override
public String getSSN() {
return rootSSN;
}
@Override
public Source fromFQN(String fqn) {
return fromFQN(fqn, getRootSource());
}
@Override
public Source fromFQN(String fqn, Source parent) {
return createFromFQN(fqn, parent);
}
@Override
public Source newFromFQN(String fqn) {
return createFromFQN(fqn, null);
}
@Override
public Source newSource(String name) {
return newSource(name, SourceType.APPL, getRootSource());
}
@Override
public Source newSource(String name, SourceType tp) {
return newSource(name, tp, getRootSource());
}
@Override
public Source newSource(String name, SourceType tp, Source parent) {
return newSource(name, tp, parent, getNameFromType("?", SourceType.USER));
}
@Override
public Source newSource(String name, SourceType tp, Source parent, String user) {
DefaultSource src = new DefaultSource(this, getNameFromType(name, tp), tp, parent, user);
src.setSSN(getSSN());
return src;
}
@Override
public Source getRootSource() {
return rootSource;
}
@Override
public GeoLocator getGeoLocator() {
return geoLocator;
}
@Override
public Map<String, Object> getConfiguration() {
return config;
}
@Override
public void setConfiguration(Map<String, Object> settings) throws ConfigException {
config = settings;
GeoLocator locator = (GeoLocator) Utils.createConfigurableObject("GeoLocator", "GeoLocator.", config);
geoLocator = locator != null? locator: geoLocator;
// initialize default geo location to the current location
String location = geoLocator.getCurrentCoords();
if (location != null) {
defaultSources[SourceType.GEOADDR.ordinal()] = geoLocator.getCurrentCoords();
}
// initialize source types for this factory
for (SourceType type: SourceType.values()) {
String typeString = type.toString().toUpperCase();
Object typeValue = config.get(typeString);
if (typeValue != null) {
defaultSources[type.ordinal()] = getNameFromType(String.valueOf(typeValue), type);
}
}
rootFqn = Utils.getString("RootFQN", settings, DEFAULT_SOURCE_ROOT_FQN);
rootSource = newFromFQN(rootFqn);
rootSSN = Utils.getString("RootSSN", settings, DEFAULT_SOURCE_ROOT_SSN);
}
/**
* <p>
* Returns current GEO location, format is implementation specific.
* Developers should override this method for specific platforms and GEO
* implementations.
* </p>
*
* @return current GEO location
*/
public String getCurrentGeoAddr() {
return defaultSources[SourceType.GEOADDR.ordinal()];
}
/**
* <p>
* Returns current data center name, format is implementation specific.
* Developers should override this method for specific platforms.
* </p>
*
* @return current data center name
*/
public String getCurrentDatacenter() {
return defaultSources[SourceType.DATACENTER.ordinal()];
}
/**
* <p>
* Returns current source name for specific source type
* </p>
* @param type source type
* @return source name associated with a given type
*/
public String getCurrentSource(SourceType type) {
return defaultSources[type.ordinal()];
}
/**
* <p>
* Obtains default name based on a given name/type pair ? name is converted into a default runtime binding.
* $property converts property to java property binding.
* Example: SERVER=? or PROCESS=$java.process, where java property must be set to java.process=value.
* </p>
*
* @param name source name
* @param type source type
*
* @return source name based on given name and type
*/
protected String getNameFromType(String name, SourceType type) {
if (name == null || name.equals("?")) {
if (type == SourceType.GEOADDR) {
String location = geoLocator.getCurrentCoords();
if (location != null) return location;
}
return defaultSources[type.ordinal()];
}
return Utils.resolve(name, UNKNOWN_SOURCE);
}
private Source createFromFQN(String fqn, Source parent) {
StringTokenizer tk = new StringTokenizer(fqn, "#");
DefaultSource child = null, root = null;
while (tk.hasMoreTokens()) {
String sName = tk.nextToken();
String[] pair = sName.split("=");
SourceType type = SourceType.valueOf(pair[0]);
DefaultSource source = new DefaultSource(this,
getNameFromType(pair[1], type),
type,
null,
getNameFromType("?", SourceType.USER));
if (child != null)
child.setSource(source);
if (root == null)
root = source;
child = source;
}
if (child != null) {
child.setSource(parent);
}
return root;
}
}