Package org.fakereplace.server

Source Code of org.fakereplace.server.FakereplaceProtocol

/*
* Copyright 2012, Stuart Douglas, and individual contributors as indicated
* by the @authors tag.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.fakereplace.server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.fakereplace.api.AttachmentKeys;
import org.fakereplace.api.Attachments;
import org.fakereplace.api.environment.ChangedClasses;
import org.fakereplace.api.environment.CurrentEnvironment;
import org.fakereplace.core.Agent;
import org.fakereplace.logging.Logger;
import org.fakereplace.replacement.AddedClass;

/**
* An implementation of the fakereplace client server protocol.
* <p/>
* The basic protocol is as follows:
* <p/>
* Client -
* Magic no 0xCAFEDEAF
* no classes (int)
* class data (1 per class)
* class name length (int)
* class name
* timestamp (long)
* <p/>
* Server -
* no classes (int)
* class data (1 per class)
* class name length
* class name
* <p/>
* Client -
* no classes (int)
* class data
* class name length
* class name
* class bytes length
* class bytes
*
* @author Stuart Douglas
*/
public class FakereplaceProtocol {

    private static final Logger log = Logger.getLogger(FakereplaceProtocol.class);

    public static void run(Socket socket) {
        DataOutputStream output = null;
        try {
            log.trace("Fakereplace update is running");
            final DataInputStream input = new DataInputStream(socket.getInputStream());
            output = new DataOutputStream(socket.getOutputStream());
            final Map<String, Long> classes = new HashMap<String, Long>();
            final Map<String, Long> resources = new HashMap<String, Long>();
            int magic = input.readInt();
            if (magic != 0xCAFEDEAF) {
                System.err.println("Fakereplace server error, wrong magic number");
                return;
            }
            final String archiveName = readString(input);

            readAvailable(input, classes);
            readAvailable(input, resources);

            log.info("Fakereplace is checking for updates classes. Client sent " + classes.size() + "classes");


            final ChangedClasses classesToReplace = CurrentEnvironment.getEnvironment().getUpdatedClasses(archiveName, classes);
            final Map<String, Class> classMap = new HashMap<String, Class>();
            output.writeInt(classesToReplace.getChanged().size() + classesToReplace.getNewClasses().size());
            for (Class clazz : classesToReplace.getChanged()) {
                final String cname = clazz.getName();
                output.writeInt(cname.length());
                output.write(cname.getBytes());
                classMap.put(cname, clazz);
            }
            for (String cname : classesToReplace.getNewClasses()) {
                output.writeInt(cname.length());
                output.write(cname.getBytes());
            }
            final Set<String> resourcesToReplace = CurrentEnvironment.getEnvironment().getUpdatedResources(archiveName, resources);
            output.writeInt(resourcesToReplace.size());
            for (String cname : resourcesToReplace) {
                output.writeInt(cname.length());
                output.write(cname.getBytes());
            }

            output.flush();

            final Set<ClassDefinition> classDefinitions = new HashSet<ClassDefinition>();
            final Set<Class<?>> replacedClasses = new HashSet<Class<?>>();
            final List<AddedClass> addedClassList = new ArrayList<AddedClass>();
            int noClasses = input.readInt();
            for (int i = 0; i < noClasses; ++i) {
                final String className = readString(input);
                int length = input.readInt();
                byte[] buffer = new byte[length];
                for (int j = 0; j < length; ++j) {
                    buffer[j] = (byte) input.read();
                }
                final Class theClass = classMap.get(className);
                if (theClass != null) {
                    classDefinitions.add(new ClassDefinition(theClass, buffer));
                    replacedClasses.add(theClass);
                } else {
                    addedClassList.add(new AddedClass(className, buffer, classesToReplace.getClassLoader()));
                }
            }

            final Map<String, byte[]> replacedResources = new HashMap<String, byte[]>();

            int noResources = input.readInt();
            for (int i = 0; i < noResources; ++i) {
                final String resourceName = readString(input);
                int length = input.readInt();
                byte[] buffer = new byte[length];
                for (int j = 0; j < length; ++j) {
                    buffer[j] = (byte) input.read();
                }
                replacedResources.put(resourceName, buffer);
            }

            final Attachments attachments = new Attachments();
            attachments.set(AttachmentKeys.DEPLOYMENT_NAME, archiveName);

            Agent.redefine(classDefinitions.toArray( new ClassDefinition[classDefinitions.size()]), addedClassList.toArray(new AddedClass[addedClassList.size()]), attachments);
            CurrentEnvironment.getEnvironment().updateResource(archiveName, replacedResources);
            output.writeInt(0);
        } catch (Exception e) {
            try {
                output.writeInt(1);
            } catch (IOException e1) {
                //ignore
            }
            e.printStackTrace();
        } finally {
            try {
                //write the result to
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void readAvailable(final DataInputStream input, final Map<String, Long> resources) throws IOException {
        int noResources = input.readInt();
        for (int i = 0; i < noResources; ++i) {
            final String resourceName = readString(input);
            long ts = input.readLong();
            resources.put(resourceName, ts);
        }
    }

    private static String readString(final DataInputStream input) throws IOException {
        int toread = input.readInt();
        byte[] buf = new byte[toread];
        int read = 0;
        while (toread > 0 && (read = input.read(buf, read, toread)) != -1) {
            toread -= read;
        }
        return new String(buf);
    }

}
TOP

Related Classes of org.fakereplace.server.FakereplaceProtocol

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.