package com.tesora.dve.variables; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import com.tesora.dve.common.catalog.CatalogDAO; import com.tesora.dve.common.catalog.CatalogDAO.CatalogDAOFactory; import com.tesora.dve.common.catalog.VariableConfig; import com.tesora.dve.errmap.AvailableErrors; import com.tesora.dve.errmap.ErrorInfo; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.exceptions.PEMappedException; import com.tesora.dve.sql.schema.VariableScopeKind; import com.tesora.dve.sql.util.Functional; // mostly just a helper class public class VariableManager { private static VariableManager instance = null; // single point of initialization, has some side effects public static VariableManager getManager() throws PEException { VariableManager vm = instance; if (vm == null) synchronized(VariableManager.class) { if (instance == null) { instance = new VariableManager(); } vm = instance; } return vm; } // not final because we could add private LinkedHashMap<String,VariableHandler<?>> handlers; private VariableManager() throws PEException { handlers = new LinkedHashMap<String,VariableHandler<?>>(); for(VariableHandler<?> vh : KnownVariables.namedHandlers) addHandler(vh); for(VariableHandler<?> vh : KnownVariables.unnamedHandlers) addHandler(vh); } public void addHandler(VariableHandler<?> vh) throws PEException { VariableHandler<?> before = handlers.put(normalize(vh.getName()),vh); if (before != null) throw new PEException("Duplicate handler for variable '" + vh.getName() + "'"); } // used in the upgrade public static String normalize(String in) { return in.toLowerCase(Locale.ENGLISH); } public List<VariableHandler<?>> getSessionHandlers() { return Functional.select(handlers.values(), VariableHandler.isSessionPredicate); } public List<VariableHandler<?>> getGlobalHandlers() { return Functional.select(handlers.values(), VariableHandler.isGlobalPredicate); } public List<VariableHandler<?>> getAllHandlers() { return Functional.toList(handlers.values()); } public VariableHandler<?> lookupMustExist(VariableStoreSource src, String name) throws PEException { VariableHandler<?> vh = handlers.get(normalize(name)); if (vh == null) { boolean verbose = false; if (src != null) verbose = KnownVariables.ERROR_MIGRATOR.getGlobalValue(src); throw new PEMappedException(new ErrorInfo(AvailableErrors.UNKNOWN_SYS_VAR,name),verbose); } return vh; } public VariableHandler<?> lookup(String name) { return handlers.get(normalize(name)); } public void initializeDynamicMBeanHandlers(VariableHandlerDynamicMBean mbean) throws PEException { if (mbean != null) { for(VariableHandler<?> vh : getGlobalHandlers()) { mbean.add(normalize(vh.getName()),vh); } } } // called during catalog initialization, i.e. CatalogHelper @SuppressWarnings("rawtypes") public Map<VariableHandler,VariableConfig> initializeCatalog(CatalogDAO c) throws PEException { // load up compiled in values. HashMap<VariableHandler,VariableConfig> out = new HashMap<VariableHandler,VariableConfig>(); for(VariableHandler<?> vh : handlers.values()) { out.put(vh,vh.initialiseCatalog(c)); } return out; } // called during server initialization @SuppressWarnings({ "rawtypes", "unchecked" }) public void initialize(CatalogDAO in) throws PEException { CatalogDAO c = in; if (c == null) c = CatalogDAOFactory.newInstance(); HashMap<VariableHandler,Object> values = new HashMap<VariableHandler,Object>(); try { for(VariableHandler<?> vh : handlers.values()) { // this will add the variable to the catalog if it is missing values.put(vh,vh.initialise(c)); } List<VariableConfig> allConfigs = c.findAllVariableConfigs(); for(VariableConfig vc : allConfigs) { VariableHandler<?> exists = handlers.get(normalize(vc.getName())); if (exists == null) { // add it exists = loadHandler(vc); // make sure we call the normal initialisation in case there is a current global value values.put(exists,exists.initialise(c)); } } } catch (PEException t) { throw t; } catch (Throwable t) { throw new PEException("Unable to initialize variables",t); } finally { if (in == null) { c.close(); } } // now initialize the global map. we put both kinds of variables into the global map: // the global variables and the session variables. the same initialization rules apply, however: // if the value isn't set, we will put it in. // note that for the hazelcast version it's good that we already persisted the values - it will load them // from there ServerGlobalVariableStore globals = ServerGlobalVariableStore.INSTANCE; for(VariableHandler vh : handlers.values()) { ValueReference vr = globals.getReference(vh); if (vr == null) { // not set at all yet, so we get to do that globals.setValue(vh, values.get(vh)); } else if (vh.getScopes().contains(VariableScopeKind.GLOBAL)) { // i.e. we got the current value, so set it vh.onGlobalValueChange(vr.get()); } } } @SuppressWarnings("rawtypes") public static ValueMetadata findMetadataConverter(String type, String varName) throws PEException { ValueMetadata<?> vm = null; for(ValueMetadata ivm : KnownVariables.defaultConverters) { if (ivm.getTypeName().equals(type)) { vm = ivm; break; } } if (vm == null) throw new PEException("Unable to determine value type for variable '" + varName + "' (type=" + type + ")"); return vm; } @SuppressWarnings({ "rawtypes", "unchecked" }) private VariableHandler loadHandler(VariableConfig vc) throws PEException { ValueMetadata<?> vm = findMetadataConverter(vc.getValueType(),vc.getName()); VariableHandler exists = new VariableHandler(vc.getName(),vm,VariableHandler.convertScopes(vc.getScopes()), vm.convertToInternal(vc.getName(),vc.getValue()), VariableHandler.convertOptions(vc.getOptions())); addHandler(exists); return exists; } // dynamically add a new variable; this just handles loading the config out of // the catalog (where it was previously persisted, possibly by some other server) // and adding it to our known variables @SuppressWarnings("rawtypes") public VariableHandler postInitializationAddVariable(String varName) throws PEException { CatalogDAO c = CatalogDAOFactory.newInstance(); try { VariableConfig vc = c.findVariableConfig(varName); if (vc == null) return null; return loadHandler(vc); } finally { c.close(); } } // for trans exec engine @SuppressWarnings({ "rawtypes", "unchecked" }) public void initialiseTransient(GlobalVariableStore globals) { for(VariableHandler vh : handlers.values()) { ValueReference vr = globals.getReference(vh); if (vr == null) { // not set at all yet, so we get to do that globals.setValue(vh,vh.getDefaultOnMissing()); } } } }