Step 1>Create A Project give the example hotswaptool Add two jar file hotswaptool 1>bcel-5.2.jar (this should be download from google) 2>tools.jar (this is coming from your jdk path like D:\Software\java\jdk1.8.0_05\lib) Step 2>Copy the below code and add in your source directory. Step 3>Run this program in java application Step 4>see the open window. Step 5>Now java hotswaptool is ready Step 6>Enabling the Debug Mode in your remote machine project where you put the hot .class file To run a regular serverless Java class Test with debugging enabled in the Oracle HotSpot JVM, you need to use the following command: java -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y Test Step 7>Start the server and call api. Step 8>If you need any business changes .class file in remote machine without restart your server goto below step Step 1>Go to your local machine and change the business logic and compile Step 2>Run the hot swap tool step 3>give the remote machine IP address step 4>give the remote machine debug port number like 8787 Step 5>browse the .class file from your local Step 6>Click the hotswap Step 7>Done Step 8>again call api see the result it will effected Step 9>Draw back of the jdb. Which is working 1>Simple variable --working 2>Existing static variable with out changes --working 3>Existing method change business logic --working 4>Existing static method change business logic --working 5>Existing inner class changes business logic --working 6>Existing inner class business logic --working Which is not working 1>Existing static variable with value changes --Not working 2>new method add --Not working 3>New static method --Not working 4>add new Enum --Not working 5>existing new enum change business value --Not working 6>add inner class --Not working 7>add new class --Not working Step 10>Suggestion from my understanding 1>Please add all .java a default serialization id. for avoid the compiler to compiler no new serialization id createion. Step 11>Thanks for your time spent :)For more understanding : click
package com.kartik.org; import javax.swing.JFrame; /** * * @author kmandal * */ public class SwapDemo { public static void main(String[] a) { Swap frame = new Swap(); frame.setTitle("Hot Swap Tool"); frame.setVisible(true); frame.setBounds(10, 10, 500, 500); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setResizable(false); frame.setLocationRelativeTo(null); } }
package com.kartik.org; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import org.apache.bcel.classfile.ClassParser; import org.apache.bcel.classfile.JavaClass; /** * * @author kmandal * */ public class Swap extends JFrame implements ActionListener,Runnable { private static final long serialVersionUID = 1L; private String ipAddress; private String portNumber; private String absoulatePath; private String realPath; private File file; public String getIpAddress() { return ipAddress; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } public String getPortNumber() { return portNumber; } public void setPortNumber(String portNumber) { this.portNumber = portNumber; } public String getAbsoulatePath() { return absoulatePath; } public void setAbsoulatePath(String absoulatePath) { this.absoulatePath = absoulatePath; } public String getRealPath() { return realPath; } public void setRealPath(String realPath) { this.realPath = realPath; } public File getFile() { return file; } public void setFile(File file) { this.file = file; } Container container=getContentPane(); //JPanel panel = new JPanel(new GridLayout(0, 1)); JButton headerLabel=new JButton("Swap Tool "); JLabel ipLabel=new JLabel("Ip Address: *"); JLabel portNoLabel=new JLabel("Port number: *"); JLabel fileChooseLabel=new JLabel("Choose File: *"); JTextField ipTextField=new JTextField(); JTextField portTextField=new JTextField(); JTextField fileName = new JTextField(); JButton browse = new JButton("Browse"); JButton loginButton=new JButton("Swap File"); JButton resetButton=new JButton("Re-set"); Swap() { //Calling methods inside constructor. setLayoutManager(); setLocationAndSize(); addComponentsToContainer(); } public void setLayoutManager() { container.setLayout(null); } public void setLocationAndSize() { headerLabel.setBounds(50,100,430,30); headerLabel.setOpaque(true); // headerLabel.setBackground(Color.GREEN); //Setting location and Size of each components using setBounds() method. ipLabel.setBounds(50,150,100,20); portNoLabel.setBounds(50,200,100,20); fileChooseLabel.setBounds(50,250,100,20); ipTextField.setBounds(150,150,200,20); portTextField.setBounds(150,200,100,20); fileName.setEditable(false); fileName.setBounds(150,250,220,20); browse.setBounds(380,250,100,20); loginButton.setBounds(50,300,100,25); resetButton.setBounds(200,300,100,25); } public void addComponentsToContainer() { container.add(headerLabel); //Adding each components to the Container container.add(ipLabel); container.add(portNoLabel); container.add(fileChooseLabel); ipTextField.addFocusListener(new FocusListener() { public void focusLost(FocusEvent fe) { setIpAddress(ipTextField.getText()); } public void focusGained(FocusEvent fe) { } }); ipTextField.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { if (ipTextField.getText().length() >= 50) e.consume(); } }); container.add(ipTextField); portTextField.addFocusListener(new FocusListener() { public void focusLost(FocusEvent fe) { setPortNumber(portTextField.getText()); } public void focusGained(FocusEvent fe) { } }); portTextField.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { char letter = e.getKeyChar(); if (portTextField.getText().length() >= 15) { e.consume(); } else if (!Character.isDigit(letter)) { e.consume(); } } }); container.add(portTextField); container.add(fileName); browse.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { if (SwingUtilities.isLeftMouseButton(evt)) { Chooser frame = new Chooser(); fileName.setText(frame.fileName); setRealPath(frame.fileName); setFile(frame.file); } } }); container.add(browse); loginButton.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { if (SwingUtilities.isLeftMouseButton(evt)) { boolean flag=validation(); if(flag){ /*Thread swapThread = new Thread(); swapThread.start(); try { System.out.println("Start the First Sleep"); Thread.sleep(5000); System.out.println("Start the hot swap");*/ hotSwap(); /*System.out.println("Start the Second Sleep"); Thread.sleep(5000); System.out.println("End the sleep"); } catch (InterruptedException e) { e.printStackTrace(); }*/ } } } }); container.add(loginButton); container.add(resetButton); } /** * * @param fullStr * @return */ private void hotSwap() { StringBuffer br = new StringBuffer(); generateComand(br); String command = br.toString(); System.out.println(command); StringBuffer br2 = new StringBuffer(); String packageName = null; File f = getFile(); String aa = f.getName(); String[] arrOfStr = aa.split("\\.", -1); String filePath = filePathMethod(getRealPath()); if (f.exists()) { ClassParser classParser = null; try { classParser = new ClassParser(filePath); } catch (IOException e) { e.printStackTrace(); } JavaClass javaClass = null; try { javaClass = classParser.parse(); } catch (IOException ioe) { System.out.println(filePath); } packageName = javaClass.getPackageName(); writeMethodInCommand(br2, packageName, arrOfStr, filePath); HotSwap h = new HotSwap(); boolean isRunning = h.isProcessRunning(command, br2.toString()); String processName = "java.exe"; if (isRunning) { h.killProcess(processName); } else { System.out.println("Not able to find the process : " + processName); } } else { System.out.println("\nFile Path not exist "); } } /** * This is find out the absoluteFilePath of a file for any server * * @param fileName * fileName * @param pathName * pathName * @return absoluteFilePath */ public String filePathMethod(String pathName) { String absoluteFilePath = ""; // String workingDir = System.getProperty("user.dir"); String runnigServerOs = System.getProperty("os.name").toLowerCase(); if (runnigServerOs.indexOf("win") >= 0) { // if windows absoluteFilePath = pathName.replaceAll("\\\\", "\\\\\\\\"); } else if (runnigServerOs.indexOf("nix") >= 0 || runnigServerOs.indexOf("nux") >= 0 || runnigServerOs.indexOf("mac") >= 0) { // if unix or mac // absoluteFilePath = workingDir + "/" + fileName; absoluteFilePath = pathName; } else { // unknow os? // absoluteFilePath = workingDir + "/" + fileName; absoluteFilePath = pathName; } System.out.println("Final filepath : " + absoluteFilePath); return absoluteFilePath; } /** * * @param br */ private void generateComand(StringBuffer br) { br.append("jdb -connect com.sun.jdi.SocketAttach:hostname="); br.append(getIpAddress()); br.append(",port="); br.append(getPortNumber()); } /** * * @param br2 * @param packageName * @param arrOfStr * @param filePath */ private void writeMethodInCommand(StringBuffer br2, String packageName, String[] arrOfStr, String filePath) { br2.append("redefine"); br2.append(" "); br2.append(packageName); br2.append("."); br2.append(arrOfStr[0]); br2.append(" "); br2.append(filePath); } @Override public void actionPerformed(ActionEvent e) { } public boolean validation() { if(getIpAddress().equals("")) { String message = "Please enter ip address properly\n"; JOptionPane.showMessageDialog(container, message, "Dialog", JOptionPane.ERROR_MESSAGE); return false; } else if(getPortNumber().equals("")) { String message = "Please enter port number\n"; JOptionPane.showMessageDialog(container, message, "Dialog", JOptionPane.ERROR_MESSAGE); return false; } else if(Integer.parseInt(getPortNumber())<=0) { String message = "Please enter port number\n"; JOptionPane.showMessageDialog(container, message, "Dialog", JOptionPane.ERROR_MESSAGE); return false; } else if(getFile().equals("")) { String message = "Please enter file which you need to swap \n"; JOptionPane.showMessageDialog(container, message, "Dialog", JOptionPane.ERROR_MESSAGE); return false; } return true; } @Override public void run() { // TODO Auto-generated method stub } }
package com.kartik.org; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; public class HotSwap { public boolean isProcessRunning(String command,String write) { boolean flag=false; try { /* String array to execute commands */ String[] commands = new String[3]; commands[0] = "cmd"; commands[1] = "/c"; /* Command you want to execute */ // command[2] = "jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.211.180,port=8999"; //commands[2] = "jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.57.66,port=8999"; commands[2] = command; /* Create process */ Process p = Runtime.getRuntime().exec(commands); /* Get OuputStream */ PrintWriter writer = new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(p.getOutputStream())), true); /* Read the output of command prompt */ BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); String line = reader.readLine(); /* Read upto end of execution */ int count=0; while (line != null) { /* Pass the value to command prompt/user input */ // writer.println("redefine com.journaldev.spring.PersonController D:\\Kartik\\Karthik\\Spring-Boot-REST\\target\\classes\\com\\journaldev\\spring\\PersonController.class"); writer.println(write); System.out.println(line); if(count>=2){ return true; }else{ line = reader.readLine(); } count=count+1; } /* The stream obtains data from the standard output stream of the process represented by this Process object. */ BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); /* The stream obtains data from the error output stream of the process represented by this Process object. */ BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); String Input; while ((Input = stdInput.readLine()) != null) { System.out.println(Input); } String Error; while ((Error = stdError.readLine()) != null) { System.out.println(Error); } } catch (Exception e) { e.printStackTrace(); } return flag; } private static final String KILL = "TASKKILL /F /IM "; public void killProcess(String serviceName) { try { Runtime.getRuntime().exec(KILL + serviceName); System.out.println(serviceName+" killed successfully!"); System.exit(0); } catch (IOException e) { e.printStackTrace(); } } }
package com.kartik.org; import java.io.File; import javax.swing.JFileChooser; import javax.swing.JFrame; /** * * @author kmandal * */ public class Chooser extends JFrame { private static final long serialVersionUID = 1L; public JFileChooser chooser; public String fileName; public File file; public Chooser() { chooser = new JFileChooser(); int r = chooser.showOpenDialog(new JFrame()); if (r == JFileChooser.APPROVE_OPTION) { fileName = chooser.getSelectedFile().getPath(); file = chooser.getSelectedFile(); } } }