Java tutorial
/** JEM, the BEE - Job Entry Manager, the Batch Execution Environment Copyright (C) 2012-2015 Marco "Fuzzo" Cuccato This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. 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 for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.pepstock.jem.gwt.server.services; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import org.apache.commons.lang3.StringUtils; import org.pepstock.jem.NodeInfoBean; import org.pepstock.jem.gwt.server.UserInterfaceMessage; import org.pepstock.jem.gwt.server.commons.DistributedTaskExecutor; import org.pepstock.jem.gwt.server.commons.GenericDistributedTaskExecutor; import org.pepstock.jem.log.LogAppl; import org.pepstock.jem.node.ConfigurationFile; import org.pepstock.jem.node.NodeInfo; import org.pepstock.jem.node.Queues; import org.pepstock.jem.node.Status; import org.pepstock.jem.node.affinity.Result; import org.pepstock.jem.node.configuration.ConfigKeys; import org.pepstock.jem.node.executors.ExecutionResult; import org.pepstock.jem.node.executors.affinity.CheckAffinityPolicy; import org.pepstock.jem.node.executors.affinity.GetAffinityPolicy; import org.pepstock.jem.node.executors.affinity.SaveAffinityPolicy; import org.pepstock.jem.node.executors.configuration.CheckHazelcastConfiguration; import org.pepstock.jem.node.executors.configuration.CheckJemConfiguration; import org.pepstock.jem.node.executors.configuration.CheckJemEnvConfiguration; import org.pepstock.jem.node.executors.configuration.GetHazelcastConfiguration; import org.pepstock.jem.node.executors.configuration.GetJemConfiguration; import org.pepstock.jem.node.executors.configuration.GetJemEnvConfiguration; import org.pepstock.jem.node.executors.configuration.SaveHazelcastConfiguration; import org.pepstock.jem.node.executors.configuration.SaveJemConfiguration; import org.pepstock.jem.node.executors.configuration.SaveJemEnvConfiguration; import org.pepstock.jem.node.executors.datasetsrules.CheckDatasetsRules; import org.pepstock.jem.node.executors.datasetsrules.GetDatasetsRules; import org.pepstock.jem.node.executors.datasetsrules.SaveDatasetsRules; import org.pepstock.jem.node.executors.nodes.Drain; import org.pepstock.jem.node.executors.nodes.GetLog; import org.pepstock.jem.node.executors.nodes.Shutdown; import org.pepstock.jem.node.executors.nodes.Start; import org.pepstock.jem.node.executors.nodes.Top; import org.pepstock.jem.node.executors.nodes.Update; import org.pepstock.jem.node.security.Permissions; import org.pepstock.jem.node.security.StringPermission; import org.pepstock.jem.util.filters.Filter; import org.pepstock.jem.util.filters.fields.NodeFilterFields; import org.pepstock.jem.util.filters.predicates.NodePredicate; import com.hazelcast.core.Cluster; import com.hazelcast.core.IMap; import com.hazelcast.core.Member; import com.hazelcast.query.Predicates.AbstractPredicate; import com.hazelcast.query.SqlPredicate; /** * Is the manager of all operations to the nodes of JEM. * UNKNOWN members are not returned. * * @author Marco "Fuzzo" Cuccato * */ public class NodesManager extends DefaultService { /** * Returns the list of all normal nodes joined the cluster. UNKNOWN members are not returned. * * @param nodesFilter filter contains all tokens to performs filtering * @return collection of nodes * @throws ServiceMessageException if any exception occurs */ public Collection<NodeInfoBean> getNodes(String nodesFilter) throws ServiceMessageException { return getNodes(nodesFilter, false); } /** * Returns the list of all swarm nodes joined the cluster. UNKNOWN members are not returned. * * @param nodesFilter filter contains all tokens to performs filtering * @return collection of nodes * @throws ServiceMessageException if any exception occurs */ public Collection<NodeInfoBean> getSwarmNodes(String nodesFilter) throws ServiceMessageException { return getNodes(nodesFilter, true); } /** * Returns the list of all nodes joined the cluster. UNKNOWN members are not returned * * @param nodesFilter filter contains all tokens to performs filtering * @param swarmNodes if true return only swarmNodes nodes, if false return only nodes that are not swarmNodes nodes * @return collection of nodes * @throws ServiceMessageException if any exception occurs */ public Collection<NodeInfoBean> getNodes(String nodesFilter, boolean swarmNodes) throws ServiceMessageException { // builds permission String permission = Permissions.SEARCH_NODES + nodesFilter.toLowerCase(); // checks if the user is authorized to get nodes // if not, this method throws an exception checkAuthorization(new StringPermission(permission)); // prepares SQL query to extract the right nodes String sqlFilter = nodesFilter.replace('.', '_'); sqlFilter = sqlFilter.replace('*', '%'); // creates SQL StringBuilder sb = new StringBuilder(); sb.append("(hostname like '").append(sqlFilter).append("'").append(" OR "); sb.append("label like '").append(sqlFilter).append("') "); if (swarmNodes) { sb.append(" AND isSwarmNode = " + swarmNodes); } List<NodeInfoBean> list = getNodesButUnknown(new SqlPredicate(sb.toString())); // if list is not empty if (!list.isEmpty()) { // sorts the list for KEY Collections.sort(list, new Comparator<NodeInfoBean>() { @Override public int compare(NodeInfoBean o1, NodeInfoBean o2) { return o1.getKey().compareTo(o2.getKey()); } }); } return list; } /** * Returns the list of all nodes joined the cluster. UNKNOWN members are not returned * * @param nodesFilter a String that will be parsed as a {@link Filter} * @return collection of nodes * @throws ServiceMessageException if any exception occurs */ public Collection<NodeInfoBean> getNodesByFilter(String nodesFilter) throws ServiceMessageException { // creates a filter object Filter filter = Filter.parseOrDefault(nodesFilter, Filter.NODE_DEFAULT_FILTER); // extract the label or hostname, if it is. // necessary to check permission because it is based on // label or hostname String nodesPermString = filter.get(NodeFilterFields.NAME.getName()); // if label is null, try with hostname if ((nodesPermString == null) || (nodesPermString.trim().length() == 0)) { nodesPermString = filter.get(NodeFilterFields.HOSTNAME.getName()); // if hostname is null as well, then use * if ((nodesPermString == null) || (nodesPermString.trim().length() == 0)) { nodesPermString = "*"; } } // creates the right permission by jlabel or hostname String permission = Permissions.SEARCH_NODES + nodesPermString.toLowerCase(); // checks if the user is authorized to get nodes // if not, this method throws an exception checkAuthorization(new StringPermission(permission)); return getNodesButUnknown(new NodePredicate(filter)); } private List<NodeInfoBean> getNodesButUnknown(AbstractPredicate predicate) throws ServiceMessageException { IMap<String, NodeInfo> nodes = getInstance().getMap(Queues.NODES_MAP); List<NodeInfoBean> list = new ArrayList<NodeInfoBean>(); Collection<NodeInfo> allNodes = null; boolean isLock = false; Lock lock = getInstance().getLock(Queues.NODES_MAP_LOCK); try { isLock = lock.tryLock(10, TimeUnit.SECONDS); if (isLock) { // gets all nodes by predicate allNodes = nodes.values(predicate); } else { throw new ServiceMessageException(UserInterfaceMessage.JEMG022E, Queues.NODES_MAP); } } catch (InterruptedException e) { throw new ServiceMessageException(UserInterfaceMessage.JEMG022E, e, Queues.NODES_MAP); } finally { // unlocks always the map if (isLock) { lock.unlock(); } } if (allNodes != null) { // gets the nodes and returns them // removing the nodes in UNKNOW // to avoid misunderstanding on UI for (NodeInfo node : allNodes) { if (!node.getStatus().equals(Status.UNKNOWN)) { list.add(node.getNodeInfoBean()); } } } return list; } /** * Drains the list of members, using a future task by executor service of Hazelcast. * * @param nodes list of members to drain * @return always <code>true</code> * @throws ServiceMessageException if any exception occurs */ public Boolean drain(Collection<NodeInfoBean> nodes) throws ServiceMessageException { // checks if the user is authorized to drain nodes // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.NODES_DRAIN)); return doNodeAction(nodes, new Drain()); } /** * Starts the list of members, using a future task by executor service of Hazelcast. * * @param nodes nodes list of members to start * @return always <code>true</code> * @throws ServiceMessageException if any exception occurs */ public Boolean start(Collection<NodeInfoBean> nodes) throws ServiceMessageException { // checks if the user is authorized to start nodes // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.NODES_START)); return doNodeAction(nodes, new Start()); } /** * Shuts down the list of members, using a future task by executor service of Hazelcast.<br> * Is not used. * * @param nodes list of nodes * @return always <code>true</code> * @throws ServiceMessageException if any exception occurs */ @SuppressWarnings("unused") private Boolean shutdown(Collection<NodeInfoBean> nodes) throws ServiceMessageException { checkAuthentication(); return doNodeAction(nodes, new Shutdown()); } /** * Execute a specific task on a set of Nodes. Be sure you check authorizations before calling this. * @param nodes the target nodes * @param executor the task to be executed * @return always <code>true</code> * @throws ServiceMessageException if any exception occours */ private Boolean doNodeAction(Collection<NodeInfoBean> nodes, Callable<ExecutionResult> executor) throws ServiceMessageException { // gets nodes map instance IMap<String, NodeInfo> membersMap = getInstance().getMap(Queues.NODES_MAP); // scans all nodes for (NodeInfoBean node : nodes) { // is not a super node and is not UNKNOWN if (!node.getStatus().equalsIgnoreCase(Status.UNKNOWN.getDescription())) { // gets key String key = node.getKey(); // checks if is in map if (membersMap.containsKey(key)) { // gets the cluster to have member object of Hazelcast // to execute the future task Cluster cluster = getInstance().getCluster(); // gets all members and scans them Set<Member> set = cluster.getMembers(); for (Member member : set) { String memberKey = member.getUuid(); // is the same member if (node.getKey().equalsIgnoreCase(memberKey)) { GenericDistributedTaskExecutor task = new GenericDistributedTaskExecutor(executor, member); task.execute(); } } } } } return Boolean.TRUE; } /** * Update the domain or static affinities of node * @param node node to update * @return always true * @throws ServiceMessageException if any exception occurs */ public Boolean update(NodeInfoBean node) throws ServiceMessageException { // checks if the user is authorized to update a node // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.NODES_UPDATE)); GenericDistributedTaskExecutor task = new GenericDistributedTaskExecutor(new Update(node), getMember(node.getKey())); task.execute(); return Boolean.TRUE; } /** * Returns the configuration file for the node * * @param node node where execute a future task to get the config file * @param what type of configuration file to return * @return Configuration file container * @throws ServiceMessageException if exception occurs */ public ConfigurationFile getNodeConfigFile(NodeInfoBean node, String what) throws ServiceMessageException { // checks if the user is authorized to read configuration // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_NODES_CONFIGURATION)); // creates the future task Callable<ConfigurationFile> executor = null; // checks if wants Hazelcast or JEM node configuration // by default is JEM node configuration if (what != null) { if (what.equalsIgnoreCase(ConfigKeys.JEM_CONFIG)) { executor = new GetJemConfiguration(); } else if (what.equalsIgnoreCase(ConfigKeys.AFFINITY)) { executor = new GetAffinityPolicy(); } else { executor = new GetJemConfiguration(); } } else { executor = new GetJemConfiguration(); } DistributedTaskExecutor<ConfigurationFile> task = new DistributedTaskExecutor<ConfigurationFile>(executor, getMember(node.getKey())); return task.getResult(); } /** * Saves the configuration file for the node * * @param node node where execute a future task to get the config file * @param file configuration file to save * @param what type of configuration file to return * @return Configuration file container * @throws ServiceMessageException if exception occurs */ public ConfigurationFile saveNodeConfigFile(NodeInfoBean node, ConfigurationFile file, String what) throws ServiceMessageException { // checks if the user is authorized to read configuration // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_NODES_CONFIGURATION)); // creates the future task Callable<ConfigurationFile> executor = null; // checks if wants Hazelcast or JEM node configuration // by default is JEM node configuration if (what != null) { if (what.equalsIgnoreCase(ConfigKeys.JEM_CONFIG)) { checkConfigFile(file.getContent(), what); executor = new SaveJemConfiguration(file); } else if (what.equalsIgnoreCase(ConfigKeys.AFFINITY)) { checkAffinityPolicy(node, file.getContent()); executor = new SaveAffinityPolicy(file); } else { executor = new SaveJemConfiguration(file); } } else { executor = new SaveJemConfiguration(file); } DistributedTaskExecutor<ConfigurationFile> task = new DistributedTaskExecutor<ConfigurationFile>(executor, getMember(node.getKey())); return task.getResult(); } /** * Checks if syntax of content is correct. * @param content content of configuration file * @param what type of config file * @return always true * @throws ServiceMessageException if any error parsing content occurs */ public Boolean checkConfigFile(String content, String what) throws ServiceMessageException { // checks if the user is authorized to read configuration // if not, this method throws an exception try { checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_NODES_CONFIGURATION)); } catch (Exception e) { LogAppl.getInstance().ignore(e.getMessage(), e); checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_CLUSTER_CONFIGURATION)); } // creates the future task Callable<Boolean> executor = null; // checks if wants Hazelcast or JEM node configuration // by default is JEM node configuration if (what != null) { if (what.equalsIgnoreCase(ConfigKeys.JEM_CONFIG)) { executor = new CheckJemConfiguration(content); } else if (what.equalsIgnoreCase(ConfigKeys.JEM_ENV_CONF)) { executor = new CheckJemEnvConfiguration(content); } else if (what.equalsIgnoreCase(ConfigKeys.HAZELCAST_CONFIG)) { executor = new CheckHazelcastConfiguration(content); } else if (what.equalsIgnoreCase(ConfigKeys.DATASETS_RULES)) { executor = new CheckDatasetsRules(content); } else { executor = new CheckJemConfiguration(content); } } else { executor = new CheckJemConfiguration(content); } DistributedTaskExecutor<Boolean> task = new DistributedTaskExecutor<Boolean>(executor, getMember()); return task.getResult(); } /** * Checks if syntax of affinity loader policy content is correct. * @param node node where execute a future task * @param content type of affinity policy * @return always true * @throws ServiceMessageException if any error parsing content occurs */ public Result checkAffinityPolicy(NodeInfoBean node, String content) throws ServiceMessageException { // checks if the user is authorized to read configuration // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_NODES_CONFIGURATION)); DistributedTaskExecutor<Result> task = new DistributedTaskExecutor<Result>(new CheckAffinityPolicy(content), getMember(node.getKey())); return task.getResult(); } /** * Returns the configuration file for the environment * * @param what type of configuration file to return * @return Configuration file container * @throws ServiceMessageException if exception occurs */ public ConfigurationFile getEnvConfigFile(String what) throws ServiceMessageException { // checks if the user is authorized to read configuration // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_CLUSTER_CONFIGURATION)); // creates the future task Callable<ConfigurationFile> executor = null; // checks if wants Hazelcast or JEM node configuration // by default is JEM node configuration if (what != null) { if (what.equalsIgnoreCase(ConfigKeys.HAZELCAST_CONFIG)) { executor = new GetHazelcastConfiguration(); } else if (what.equalsIgnoreCase(ConfigKeys.JEM_ENV_CONF)) { executor = new GetJemEnvConfiguration(); } else if (what.equalsIgnoreCase(ConfigKeys.DATASETS_RULES)) { executor = new GetDatasetsRules(); } else { executor = new GetJemEnvConfiguration(); } } else { executor = new GetJemEnvConfiguration(); } DistributedTaskExecutor<ConfigurationFile> task = new DistributedTaskExecutor<ConfigurationFile>(executor, getMember()); return task.getResult(); } /** * Returns the configuration file for the environment after saving it * * @param file configuration file to save * @param what type of configuration file to return * @return Configuration new file container * @throws ServiceMessageException if exception occurs */ public ConfigurationFile saveEnvConfigFile(ConfigurationFile file, String what) throws ServiceMessageException { // checks if the user is authorized to read configuration // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_CLUSTER_CONFIGURATION)); // creates the future task Callable<ConfigurationFile> executor = null; // checks if wants Hazelcast or JEM node configuration // by default is JEM node configuration if (what != null) { if (what.equalsIgnoreCase(ConfigKeys.HAZELCAST_CONFIG)) { checkConfigFile(file.getContent(), what); executor = new SaveHazelcastConfiguration(file); } else if (what.equalsIgnoreCase(ConfigKeys.JEM_ENV_CONF)) { checkConfigFile(file.getContent(), what); executor = new SaveJemEnvConfiguration(file); } else if (what.equalsIgnoreCase(ConfigKeys.DATASETS_RULES)) { checkConfigFile(file.getContent(), what); executor = new SaveDatasetsRules(file); } else { executor = new SaveJemEnvConfiguration(file); } } else { executor = new SaveJemEnvConfiguration(file); } DistributedTaskExecutor<ConfigurationFile> task = new DistributedTaskExecutor<ConfigurationFile>(executor, getMember()); return task.getResult(); } /** * Returns the top command result * * @param node node where execute a future task to get top command * @return content file in String * @throws ServiceMessageException if exception occurs */ public String top(NodeInfoBean node) throws ServiceMessageException { // checks if the user is authorized to performs commands // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_NODES_COMMANDS)); DistributedTaskExecutor<String> task = new DistributedTaskExecutor<String>(new Top(), getMember(node.getKey())); return task.getResult(); } /** * Returns part of JEM node log * * @param node node where execute a future task to get top command * @return content file in String * @throws ServiceMessageException if exception occurs */ public String log(NodeInfoBean node) throws ServiceMessageException { // checks if the user is authorized to performs commands // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_NODES_COMMANDS)); DistributedTaskExecutor<String> task = new DistributedTaskExecutor<String>(new GetLog(), getMember(node.getKey())); return task.getResult(); } /** * Returns the HAZELCAST cluster status which is the list of all members.<br> * This is a sampl output format:<br> * <code> * Members [2] { Member [127.0.0.1]:5710 this Member [127.0.0.1]:5711 } * </code> * * @param node node where execute a future task to get top command * @return content file in String * @throws ServiceMessageException if exception occurs */ public String displayCluster(NodeInfoBean node) throws ServiceMessageException { // checks if the user is authorized to performs commands // if not, this method throws an exception checkAuthorization(new StringPermission(Permissions.ADMINISTRATION_NODES_COMMANDS)); // gets hzelcast cluster Cluster cluster = getInstance().getCluster(); // scans all members creating a stringbuilder // with HC format StringBuilder result = new StringBuilder("Members [").append(cluster.getMembers().size()).append("] {") .append("\n"); for (Member member : cluster.getMembers()) { // adds dinamically the label "this" // based on node passed as argument String memberString = StringUtils.remove(member.toString(), " this"); if (node.getKey().equals(member.getUuid())) { memberString = memberString + " this"; } result.append(" ").append(memberString).append("\n"); } result.append("}\n"); return result.toString(); } }