Java tutorial
/** * $Header: /home/master/nWave-DM-Common/src/com/npower/dm/processor/ProfileReAssignmentProcessor.java,v 1.29 2008/12/12 04:16:10 zhao Exp $ * $Revision: 1.29 $ * $Date: 2008/12/12 04:16:10 $ * * =============================================================================================== * License, Version 1.1 * * Copyright (c) 1994-2006 NPower Network Software Ltd. All rights reserved. * * This SOURCE CODE FILE, which has been provided by NPower as part * of a NPower product for use ONLY by licensed users of the product, * includes CONFIDENTIAL and PROPRIETARY information of NPower. * * USE OF THIS SOFTWARE IS GOVERNED BY THE TERMS AND CONDITIONS * OF THE LICENSE STATEMENT AND LIMITED WARRANTY FURNISHED WITH * THE PRODUCT. * * IN PARTICULAR, YOU WILL INDEMNIFY AND HOLD NPower, ITS RELATED * COMPANIES AND ITS SUPPLIERS, HARMLESS FROM AND AGAINST ANY CLAIMS * OR LIABILITIES ARISING OUT OF THE USE, REPRODUCTION, OR DISTRIBUTION * OF YOUR PROGRAMS, INCLUDING ANY CLAIMS OR LIABILITIES ARISING OUT OF * OR RESULTING FROM THE USE, MODIFICATION, OR DISTRIBUTION OF PROGRAMS * OR FILES CREATED FROM, BASED ON, AND/OR DERIVED FROM THIS SOURCE * CODE FILE. * =============================================================================================== */ package com.npower.dm.processor; import java.io.Serializable; import java.security.Principal; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import sync4j.framework.core.dm.ddf.DevInfo; import sync4j.framework.engine.dm.AddManagementOperation; import sync4j.framework.engine.dm.DeviceDMState; import sync4j.framework.engine.dm.GetManagementOperation; import sync4j.framework.engine.dm.ManagementException; import sync4j.framework.engine.dm.ManagementOperation; import sync4j.framework.engine.dm.ManagementOperationResult; import sync4j.framework.engine.dm.ManagementProcessor; import sync4j.framework.engine.dm.ReplaceManagementOperation; import sync4j.framework.engine.dm.SessionContext; import sync4j.framework.engine.dm.TreeManagementOperation; import sync4j.framework.engine.dm.TreeNode; import com.npower.dm.core.APLinkValueNotFoundException; import com.npower.dm.core.DDFNode; import com.npower.dm.core.DMException; import com.npower.dm.core.Device; import com.npower.dm.core.Model; import com.npower.dm.core.ProfileAssignment; import com.npower.dm.core.ProfileConfig; import com.npower.dm.core.ProfileMapping; import com.npower.dm.core.ProfileNodeMapping; import com.npower.dm.core.ProfileTemplate; import com.npower.dm.core.ProvisionJob; import com.npower.dm.management.ManagementBeanFactory; import com.npower.dm.management.ProfileAssignmentBean; import com.npower.dm.management.ProvisionJobBean; import com.npower.dm.server.engine.EngineConfig; import com.npower.dm.util.DMUtil; /** * @author Zhao DongLu * @version $Revision: 1.29 $ $Date: 2008/12/12 04:16:10 $ */ public class ProfileReAssignmentProcessor extends BaseProcessor implements ManagementProcessor, Serializable { private static transient Log log = LogFactory.getLog(ProfileReAssignmentProcessor.class); /** * Hold the operations which are waited to return for getNextOperations(). */ private List<ManagementOperation> queuedOperations = null; /** * Hold the RootNode Path of ProfileAssign */ private String profileRootNodePath = null; /** * Hold the nodes which wait to be processed */ private Map<DDFNode, Object> waitedNodeMaps = new TreeMap<DDFNode, Object>(); /** * Hold the mapping nodePath and DDFNode */ private Map<String, DDFNode> nodePathMaps = new TreeMap<String, DDFNode>(); /** * Hold the no-name-node's name generated by this processor. */ private Map<DDFNode, String> nameMaps = new TreeMap<DDFNode, String>(); /** * */ private boolean success = true; private int nameCounter = 0; /** * Indicate the operation mode: true is Replace, false is Add */ private boolean deleteProfileRootNodePath = false; /** * Default constructor */ public ProfileReAssignmentProcessor() { super(); } /** * Compile the ProfileAssignment to a map<DDFNode, value). * @param factory * ManagementBeanFactory * @return * @throws DMException * @throws ManagementException */ private Map<DDFNode, Object> compileToNodeMap(ManagementBeanFactory factory) throws DMException, ManagementException { ProfileAssignment assignment = getCurrentProfileAssignment(factory); ProfileConfig config = assignment.getProfileConfig(); ProfileTemplate template = config.getProfileTemplate(); Device device = assignment.getDevice(); Model model = device.getModel(); ProfileMapping mapping = model.getProfileMap(template); // Caculate the rootPath this.profileRootNodePath = assignment.getProfileRootNodePath(); String rootNodeName = BaseProcessor.getNodeNameFromNodePath(this.profileRootNodePath); DDFNode rootNode = mapping.getRootDDFNode(); if (this.profileRootNodePath == null || rootNodeName == null) { this.profileRootNodePath = rootNode.getNodePath(); } else { this.nameMaps.put(rootNode, rootNodeName); this.nodePathMaps.put(this.profileRootNodePath, rootNode); } Map<DDFNode, Object> result = new TreeMap<DDFNode, Object>(); Set<ProfileNodeMapping> nodeMappings = mapping.getProfileNodeMappings(); ProvisionJobBean jobBean = factory.createProvisionJobBean(); for (ProfileNodeMapping nodeMapping : nodeMappings) { DDFNode node = nodeMapping.getDdfNode(); // Caculate value String value = null; try { Object v = jobBean.caculateProfileAssignmentValue(assignment, nodeMapping); if (v != null) { value = v.toString(); } } catch (APLinkValueNotFoundException ex) { // Could not found ProfileAssignment linked by current profile assgingment continue; } // Put value into mapping tables. result.put(node, value); // NoNameNode, resultMap DDFNode parentNode = node.getParentDDFNode(); while (parentNode != null) { if (parentNode.getName() == null && !result.containsKey(parentNode)) { result.put(parentNode, null); } parentNode = parentNode.getParentDDFNode(); } } // Debug: List DDFNode To Value Map if (log.isDebugEnabled()) { log.debug("Profile Assignment Mapping ... "); for (DDFNode node : result.keySet()) { Object v = result.get(node); log.debug("DDFNode: \"" + node.getNodePath() + "\" with value: " + v); } } return result; } /** * Get current profile assignment. * @param factory * @return * @throws DMException * @throws ManagementException */ private ProfileAssignment getCurrentProfileAssignment(ManagementBeanFactory factory) throws DMException, ManagementException { ProvisionJobBean jobBean = factory.createProvisionJobBean(); ProvisionJob job = jobBean.loadJobByID(this.sessionContext.getDmstate().mssid); if (job == null) { throw new DMException("Could not found the jobID: " + this.sessionContext.getDmstate().mssid); } if (!job.getJobType().equalsIgnoreCase(ProvisionJob.JOB_TYPE_RE_ASSIGN_PROFILE)) { throw new DMException("The job's type wrong, must assign a assignment job to this processor. jobID: " + this.sessionContext.getDmstate().mssid); } ProfileAssignment profileAssignment = jobBean.getProfileAssignment(job, this.getDevice(factory)); return profileAssignment; } /** * Generator a Node name: * Name_Prefix + counter * * @param node * @return */ private String generateNodeName(DDFNode node) { //String newName = "" + System.currentTimeMillis(); nameCounter++; String newName = DMUtil.NAME_PREFIX_FOR_NO_NAME_NODE + nameCounter; this.nameMaps.put(node, newName); return newName; } /** * caculate the nodePath. * If the node's name is null, will instead with Map of this.nameMaps. * The path will start with "./" * @return */ private String caculateNodePath(DDFNode node) { StringBuffer result = new StringBuffer(); String name = node.getName(); if (name == null) { if (this.nameMaps.containsKey(node)) { name = this.nameMaps.get(node); } else { name = this.generateNodeName(node); } } result.append(name); DDFNode parent = node.getParentDDFNode(); while (parent != null) { result.insert(0, "/"); name = parent.getName(); if (name == null) { if (this.nameMaps.containsKey(parent)) { name = this.nameMaps.get(parent); } else { throw new RuntimeException("Parent node haven't been specified name."); } } result.insert(0, name); parent = parent.getParentDDFNode(); } String path = result.toString(); if (!path.startsWith("./")) { return "./" + path; } else { return path; } } /** * caculate the nodePath. * If the node's name is null, will instead with Map of this.nameMaps. * The path will start with "./" * @return */ private String getNodePath(DDFNode node) { StringBuffer result = new StringBuffer(); String name = node.getName(); if (name == null) { if (this.nameMaps.containsKey(node)) { name = this.nameMaps.get(node); } else { throw new RuntimeException("node haven't been specified name."); } } result.append(name); DDFNode parent = node.getParentDDFNode(); while (parent != null) { result.insert(0, "/"); name = parent.getName(); if (name == null) { if (this.nameMaps.containsKey(parent)) { name = this.nameMaps.get(parent); } else { throw new RuntimeException("Parent node haven't been specified name."); } } result.insert(0, name); parent = parent.getParentDDFNode(); } String path = result.toString(); if (!path.startsWith("./")) { return "./" + path; } else { return path; } } /** * Get next DDFNode from queue. * * @return */ private DDFNode getNextDDFNode() { Set<DDFNode> nodes = this.waitedNodeMaps.keySet(); if (nodes.isEmpty()) { return null; } else { Iterator<DDFNode> iter = nodes.iterator(); DDFNode node = iter.next(); return node; } } /** * Get, Add. * */ private void fillGetOperations() { // The queued operations is empty and not finished. for (DDFNode node : this.waitedNodeMaps.keySet()) { String name = node.getName(); if (name == null) { /* if (!this.queuedOperations.isEmpty()) { break; } */ String nodePath = this.caculateNodePath(node); GetManagementOperation oper = new GetManagementOperation(); TreeNode tNode = new TreeNode(nodePath, null); oper.addTreeNode(tNode); this.nodePathMaps.put(nodePath, node); //this.waitedNodeMaps.remove(node); this.queuedOperations.add(oper); } } // Debug: List NodePath-To-DDF Map if (log.isDebugEnabled()) { log.debug("Stage#2: NodePath-To-DDFNode Mapping ... "); for (String nodePath : this.nodePathMaps.keySet()) { DDFNode node = this.nodePathMaps.get(nodePath); log.debug("NodePath: \"" + nodePath + "\" map to DDF: " + node.getNodePath()); } } } /** * The readObject method is responsible for reading from the stream and restoring the classes fields, * and restore the transient fields. */ protected void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { super.readObject(in); log = LogFactory.getLog(ProfileReAssignmentProcessor.class); } // Public methods ***************************************************************************************** // Implements ManagementProcessor interface *************************************************************** /** * Called when a management session is started for the given principal. * sessionId is the content of the SessionID element of the OTA DM message. * * @param sessionId the content of the SessionID element of the OTA DM message * @param principal the principal who started the management session * @param type the management session type (as specified in the message Alert) * @param devInfo device info of the device under management * @param dmstate device management state * * @throws ManagementException in case of errors * * @see com.npower.dm.processor.BaseProcessor#beginSession(sync4j.framework.engine.dm.SessionContext) */ @Override public void beginSession(SessionContext context) throws ManagementException { this.sessionContext = context; String sessionId = context.getSessionId(); Principal principal = context.getPrincipal(); int type = context.getType(); DevInfo devInfo = context.getDevInfo(); if (log.isDebugEnabled()) { log.debug("Starting a new DM management session"); log.debug("sessionId: " + sessionId); log.debug("principal: " + principal); log.debug("type: " + type); log.debug("deviceId: " + devInfo); } ManagementBeanFactory factory = null; try { factory = ManagementBeanFactory.newInstance(EngineConfig.getProperties()); // Load Device boundled with this Session String deviceExternalID = this.sessionContext.getDmstate().deviceId; Device device = loadDeviceByExternalID(factory, deviceExternalID); if (device == null) { throw new ManagementException("Could not load device: from DM inventory."); } this.setDeviceID(device.getID()); // Set the job status setJobStatus4BeginSession(); // Update DevInfo this.updateDevInfo(devInfo); this.queuedOperations = new ArrayList<ManagementOperation>(); this.waitedNodeMaps = this.compileToNodeMap(factory); this.fillGetOperations(); } catch (Exception ex) { throw new ManagementException("Error in beginSession: ", ex); } finally { if (factory != null) { factory.release(); } } } /** * Called when the management session is closed. CompletionCode can be one * of: * <ul> * <li>DM_SESSION_SUCCESS</li> * <li>DM_SESSION_ABORT</li> * <li>DM_SESSION_FAILED</li> * * CompletionCode defined by DeviceDMState.STATE_XXXX * * @param completionCode the management session competion code * * @throws ManagementException in case of errors * * @see sync4j.framework.engine.dm.ManagementProcessor#endSession(int) */ public void endSession(int completionCode) throws ManagementException { if (log.isDebugEnabled()) { log.debug("End a DM management session with sessionId: " + sessionContext.getSessionId()); } ManagementBeanFactory factory = null; try { // update the jobStatus for end session setJobStatus4EndSession(completionCode); factory = ManagementBeanFactory.newInstance(EngineConfig.getProperties()); if (this.success && completionCode == DeviceDMState.STATE_COMPLETED) { // ProfileAssignment ProfileAssignment profileAssignment = this.getCurrentProfileAssignment(factory); ProfileConfig config = profileAssignment.getProfileConfig(); ProfileTemplate template = config.getProfileTemplate(); Model model = this.getDevice(factory).getModel(); ProfileMapping mapping = model.getProfileMap(template); DDFNode rootNode = mapping.getRootDDFNode(); String profileRootNodePath = null; for (String path : this.nodePathMaps.keySet()) { DDFNode node = this.nodePathMaps.get(path); if (node.getID() == rootNode.getID()) { profileRootNodePath = path; break; } } assert profileRootNodePath != null : "Could not find the root node path for ProfileAssignment."; ProfileAssignmentBean bean = factory.createProfileAssignmentBean(); profileAssignment.setProfileRootNodePath(profileRootNodePath); factory.beginTransaction(); profileAssignment.setLastSentToDevice(new Date()); bean.update(profileAssignment); factory.commit(); // Submit a discovery job to discover the device tree. ProvisionJobBean jobBean = factory.createProvisionJobBean(); ProvisionJob job = jobBean.loadJobByID(this.sessionContext.getDmstate().mssid); this.submitDiscoveryJob(job.getID(), new String[] { profileRootNodePath }); } } catch (Exception ex) { if (factory != null) { factory.rollback(); } throw new ManagementException("Could not load device: from DM inventory.", ex); } finally { if (factory != null) { factory.release(); } } } /** * Called to retrieve the next management operations to be performed. * * @returns an array of ManagementOperation representing the management * operations to be performed. * * @throws ManagementException in case of errors * * @see sync4j.framework.engine.dm.ManagementProcessor#getNextOperations() */ public ManagementOperation[] getNextOperations() throws ManagementException { if (!this.queuedOperations.isEmpty()) { this.appendDummyOperation(this.queuedOperations); return (ManagementOperation[]) this.queuedOperations.toArray(new ManagementOperation[0]); } if (this.waitedNodeMaps.isEmpty()) { // Profile has been push to terminal. all of operation is finished. return new ManagementOperation[0]; } List<ManagementOperation> operatoins = new ArrayList<ManagementOperation>(); if (this.deleteProfileRootNodePath) { // Root node exists! delete it. //DeleteManagementOperation oper = new DeleteManagementOperation(); //TreeNode tNode = new TreeNode(this.profileRootNodePath, null); //oper.addTreeNode(tNode); } for (DDFNode node = this.getNextDDFNode(); node != null;) { // Retrieve value for this DDF Node Object value = this.waitedNodeMaps.get(node); TreeManagementOperation oper = null; String nodePath = this.getNodePath(node); if (this.deleteProfileRootNodePath) { // Update node if (!nodePath.equals(this.profileRootNodePath)) { if (node.imply(DDFNode.ACCESS_TYPE_REPLACE) && !node.getFormat().equals(DDFNode.DDF_FORMAT_NODE)) { oper = new ReplaceManagementOperation(); } } } else { if (node.imply(DDFNode.ACCESS_TYPE_ADD)) { oper = new AddManagementOperation(); } else if (!node.getFormat().equals(DDFNode.DDF_FORMAT_NODE)) { // If the node do not permit to add operation. oper = new ReplaceManagementOperation(); } } if (oper != null) { TreeNode tNode = null; if (node.getFormat().equals(DDFNode.DDF_FORMAT_NODE)) { tNode = new TreeNode(nodePath); tNode.setFormat(DDFNode.DDF_FORMAT_NODE); } else { tNode = new TreeNode(nodePath, value); } oper.addTreeNode(tNode); operatoins.add(oper); } this.nodePathMaps.put(nodePath, node); this.waitedNodeMaps.remove(node); // Get Next Node node = this.getNextDDFNode(); } this.appendDummyOperation(operatoins); ManagementOperation[] operations = (ManagementOperation[]) operatoins.toArray(new ManagementOperation[0]); return operations; } /** * Called to set the results of a set of management operations. * * @param results the results of a set of management operations. * * @throws ManagementException in case of errors * * @see sync4j.framework.engine.dm.ManagementProcessor#setOperationResults(sync4j.framework.engine.dm.ManagementOperationResult[]) */ public void setOperationResults(ManagementOperationResult[] results) throws ManagementException { step++; // Checking status of operation List<ManagementOperation> newQueuedOperations = new ArrayList<ManagementOperation>(); for (ManagementOperationResult result : results) { String command = result.getCommand(); int status = result.getStatusCode(); if (command.equalsIgnoreCase("Get")) { if (this.deleteProfileRootNodePath) { // Root node exists, and bypass other Result Get. break; } if (status == 200) { // Already exists Map<String, Object> nodes = result.getNodes(); for (String oldPath : nodes.keySet()) { if (oldPath.equals(this.profileRootNodePath)) { // Set the flag , notify getNextOperations() adding a Delete Operation. this.deleteProfileRootNodePath = true; break; } DDFNode ddfNode = this.nodePathMaps.get(oldPath); String newNodePath = this.caculateNodePath(ddfNode); GetManagementOperation oper = new GetManagementOperation(); TreeNode tNode = new TreeNode(newNodePath, null); oper.addTreeNode(tNode); this.nodePathMaps.remove(oldPath); this.nodePathMaps.put(newNodePath, ddfNode); newQueuedOperations.add(oper); } continue; } continue; } else if (status == 200) { continue; } // Un-handle error this.success = false; log.error("Client response an error in ProfileAssignmentProcessor, Command: " + command + ", status: " + status + ", Detail: "); Map<String, Object> nodes = result.getNodes(); for (String oldPath : nodes.keySet()) { log.error("Target URI: " + oldPath); log.error("Value: " + nodes.get(oldPath)); } // Throw exception to terminate this session. throw new ManagementException("Client response an error in ProfileAssignmentProcessor, Command: " + command + ", status: " + status); } // re-create a new Queue. this.queuedOperations = newQueuedOperations; } }