org.eclipse.flux.core.Repository.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.flux.core.Repository.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2014 Pivotal Software, Inc. and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.flux.core;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentMap;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * @author Martin Lippert
 */
public class Repository {

    private String username;
    private IMessagingConnector messagingConnector;

    private ConcurrentMap<String, ConnectedProject> syncedProjects;
    private Collection<IRepositoryListener> repositoryListeners;

    private static int GET_PROJECT_CALLBACK = "Repository - getProjectCallback".hashCode();
    private static int GET_RESOURCE_CALLBACK = "Repository - getResourceCallback".hashCode();

    public Repository(IMessagingConnector messagingConnector, String user) {
        this.username = user;
        this.messagingConnector = messagingConnector;

        this.syncedProjects = new ConcurrentHashMap<String, ConnectedProject>();
        this.repositoryListeners = new ConcurrentLinkedDeque<>();

        this.messagingConnector.addConnectionListener(new IConnectionListener() {
            @Override
            public void connected() {
                connect();
            }

            @Override
            public void disconnected() {
            }
        });

        IMessageHandler resourceChangedHandler = new AbstractMessageHandler("resourceChanged") {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                updateResource(message);
            }
        };
        this.messagingConnector.addMessageHandler(resourceChangedHandler);

        IMessageHandler resourceCreatedHandler = new AbstractMessageHandler("resourceCreated") {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                createResource(message);
            }
        };
        this.messagingConnector.addMessageHandler(resourceCreatedHandler);

        IMessageHandler resourceDeletedHandler = new AbstractMessageHandler("resourceDeleted") {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                deleteResource(message);
            }
        };
        this.messagingConnector.addMessageHandler(resourceDeletedHandler);

        IMessageHandler getProjectsRequestHandler = new AbstractMessageHandler("getProjectsRequest") {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                getProjects(message);
            }
        };
        this.messagingConnector.addMessageHandler(getProjectsRequestHandler);

        IMessageHandler getProjectRequestHandler = new AbstractMessageHandler("getProjectRequest") {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                getProject(message);
            }
        };
        this.messagingConnector.addMessageHandler(getProjectRequestHandler);

        IMessageHandler getProjectResponseHandler = new CallbackIDAwareMessageHandler("getProjectResponse",
                Repository.GET_PROJECT_CALLBACK) {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                getProjectResponse(message);
            }
        };
        this.messagingConnector.addMessageHandler(getProjectResponseHandler);

        IMessageHandler getResourceRequestHandler = new AbstractMessageHandler("getResourceRequest") {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                try {
                    final String resourcePath = message.getString("resource");

                    if (resourcePath.startsWith("classpath:")) {
                        getClasspathResource(message);
                    } else {
                        getResource(message);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        this.messagingConnector.addMessageHandler(getResourceRequestHandler);

        IMessageHandler getResourceResponseHandler = new CallbackIDAwareMessageHandler("getResourceResponse",
                Repository.GET_RESOURCE_CALLBACK) {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                getResourceResponse(message);
            }
        };
        this.messagingConnector.addMessageHandler(getResourceResponseHandler);

        IMessageHandler getMetadataRequestHandler = new AbstractMessageHandler("getMetadataRequest") {
            @Override
            public void handleMessage(String messageType, JSONObject message) {
                getMetadata(message);
            }
        };
        this.messagingConnector.addMessageHandler(getMetadataRequestHandler);
    }

    public String getUsername() {
        return this.username;
    }

    protected void connect() {
        for (String projectName : syncedProjects.keySet()) {
            sendProjectConnectedMessage(projectName);
            syncConnectedProject(projectName);
        }
    }

    public boolean isConnected() {
        return messagingConnector.isConnected();
    }

    public ConnectedProject getProject(IProject project) {
        return getProject(project.getName());
    }

    public ConnectedProject getProject(String projectName) {
        return this.syncedProjects.get(projectName);
    }

    public boolean isConnected(IProject project) {
        return this.syncedProjects.containsKey(project.getName());
    }

    public boolean isConnected(String project) {
        return this.syncedProjects.containsKey(project);
    }

    public void addProject(IProject project) {
        String projectName = project.getName();
        if (!this.syncedProjects.containsKey(projectName)) {
            this.syncedProjects.put(projectName, new ConnectedProject(project));
            notifyProjectConnected(project);

            if (isConnected()) {
                sendProjectConnectedMessage(projectName);
                syncConnectedProject(projectName);
            }
        }
    }

    public void removeProject(IProject project) {
        String projectName = project.getName();
        if (this.syncedProjects.containsKey(projectName)) {
            this.syncedProjects.remove(projectName);
            notifyProjectDisonnected(project);

            if (isConnected()) {
                try {
                    JSONObject message = new JSONObject();
                    message.put("username", this.username);
                    message.put("project", projectName);
                    messagingConnector.send("projectDisconnected", message);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    protected void syncConnectedProject(String projectName) {
        try {
            JSONObject message = new JSONObject();
            message.put("username", this.username);
            message.put("project", projectName);
            message.put("includeDeleted", true);
            message.put("callback_id", GET_PROJECT_CALLBACK);
            messagingConnector.send("getProjectRequest", message);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    protected void sendProjectConnectedMessage(String projectName) {
        try {
            JSONObject message = new JSONObject();
            message.put("username", this.username);
            message.put("project", projectName);
            messagingConnector.send("projectConnected", message);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void getProjects(JSONObject request) {
        try {
            int callbackID = request.getInt("callback_id");
            String sender = request.getString("requestSenderID");
            String username = request.getString("username");

            if (this.username.equals(username)) {
                JSONArray projects = new JSONArray();
                for (String projectName : this.syncedProjects.keySet()) {
                    JSONObject proj = new JSONObject();
                    proj.put("name", projectName);
                    projects.put(proj);
                }

                JSONObject message = new JSONObject();
                message.put("callback_id", callbackID);
                message.put("requestSenderID", sender);
                message.put("username", this.username);
                message.put("projects", projects);

                messagingConnector.send("getProjectsResponse", message);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void getProject(JSONObject request) {
        try {
            final int callbackID = request.getInt("callback_id");
            final String sender = request.getString("requestSenderID");
            final String projectName = request.getString("project");
            final String username = request.getString("username");

            final ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null) {

                final JSONArray files = new JSONArray();

                IProject project = connectedProject.getProject();

                try {
                    project.accept(new IResourceVisitor() {
                        @Override
                        public boolean visit(IResource resource) throws CoreException {
                            JSONObject projectResource = new JSONObject();
                            String path = resource.getProjectRelativePath().toString();
                            try {
                                projectResource.put("path", path);
                                projectResource.put("timestamp", connectedProject.getTimestamp(path));
                                projectResource.put("hash", connectedProject.getHash(path));

                                if (resource instanceof IFile) {
                                    projectResource.put("type", "file");
                                } else if (resource instanceof IFolder) {
                                    projectResource.put("type", "folder");
                                }

                                files.put(projectResource);
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                            return true;
                        }
                    }, IResource.DEPTH_INFINITE, IContainer.EXCLUDE_DERIVED);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                JSONObject message = new JSONObject();
                message.put("callback_id", callbackID);
                message.put("requestSenderID", sender);
                message.put("username", this.username);
                message.put("project", projectName);
                message.put("username", this.username);
                message.put("files", files);

                messagingConnector.send("getProjectResponse", message);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void getProjectResponse(JSONObject response) {
        try {
            final String username = response.getString("username");
            final String projectName = response.getString("project");
            final JSONArray files = response.getJSONArray("files");
            final JSONArray deleted = response.optJSONArray("deleted");

            ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null) {

                for (int i = 0; i < files.length(); i++) {
                    JSONObject resource = files.getJSONObject(i);

                    String resourcePath = resource.getString("path");
                    long timestamp = resource.getLong("timestamp");

                    String type = resource.optString("type");
                    String hash = resource.optString("hash");

                    boolean newFile = type != null && type.equals("file")
                            && !connectedProject.containsResource(resourcePath);
                    boolean updatedFileTimestamp = type != null && type.equals("file")
                            && connectedProject.containsResource(resourcePath)
                            && connectedProject.getHash(resourcePath).equals(hash)
                            && connectedProject.getTimestamp(resourcePath) < timestamp;
                    boolean updatedFile = type != null && type.equals("file")
                            && connectedProject.containsResource(resourcePath)
                            && !connectedProject.getHash(resourcePath).equals(hash)
                            && connectedProject.getTimestamp(resourcePath) < timestamp;

                    if (newFile || updatedFile) {
                        JSONObject message = new JSONObject();
                        message.put("callback_id", GET_RESOURCE_CALLBACK);
                        message.put("project", projectName);
                        message.put("username", this.username);
                        message.put("resource", resourcePath);
                        message.put("timestamp", timestamp);
                        message.put("hash", hash);

                        messagingConnector.send("getResourceRequest", message);
                    }

                    if (updatedFileTimestamp) {
                        connectedProject.setTimestamp(resourcePath, timestamp);
                        IResource file = connectedProject.getProject().findMember(resourcePath);
                        file.setLocalTimeStamp(timestamp);
                    }

                    boolean newFolder = type != null && type.equals("folder")
                            && !connectedProject.containsResource(resourcePath);
                    boolean updatedFolder = type != null && type.equals("folder")
                            && connectedProject.containsResource(resourcePath)
                            && !connectedProject.getHash(resourcePath).equals(hash)
                            && connectedProject.getTimestamp(resourcePath) < timestamp;

                    if (newFolder) {
                        IProject project = connectedProject.getProject();
                        IFolder folder = project.getFolder(resourcePath);

                        connectedProject.setHash(resourcePath, hash);
                        connectedProject.setTimestamp(resourcePath, timestamp);

                        folder.create(true, true, null);
                        folder.setLocalTimeStamp(timestamp);
                    } else if (updatedFolder) {
                    }
                }

                if (deleted != null) {
                    for (int i = 0; i < deleted.length(); i++) {
                        JSONObject deletedResource = deleted.getJSONObject(i);

                        String resourcePath = deletedResource.getString("path");
                        long deletedTimestamp = deletedResource.getLong("timestamp");

                        IProject project = connectedProject.getProject();
                        IResource resource = project.findMember(resourcePath);

                        if (resource != null && resource.exists()
                                && (resource instanceof IFile || resource instanceof IFolder)) {
                            long localTimestamp = connectedProject.getTimestamp(resourcePath);

                            if (localTimestamp < deletedTimestamp) {
                                resource.delete(true, null);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void getResource(JSONObject request) {
        try {
            final String username = request.getString("username");
            final int callbackID = request.getInt("callback_id");
            final String sender = request.getString("requestSenderID");
            final String projectName = request.getString("project");
            final String resourcePath = request.getString("resource");

            ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null
                    && connectedProject.containsResource(resourcePath)) {
                IProject project = connectedProject.getProject();

                if (request.has("timestamp")
                        && request.getLong("timestamp") != connectedProject.getTimestamp(resourcePath)) {
                    return;
                }

                IResource resource = project.findMember(resourcePath);

                JSONObject message = new JSONObject();
                message.put("callback_id", callbackID);
                message.put("requestSenderID", sender);
                message.put("username", this.username);
                message.put("project", projectName);
                message.put("resource", resourcePath);
                message.put("timestamp", connectedProject.getTimestamp(resourcePath));
                message.put("hash", connectedProject.getHash(resourcePath));

                if (resource instanceof IFile) {
                    if (request.has("hash")
                            && !request.getString("hash").equals(connectedProject.getHash(resourcePath))) {
                        return;
                    }

                    IFile file = (IFile) resource;

                    ByteArrayOutputStream array = new ByteArrayOutputStream();
                    if (!file.isSynchronized(IResource.DEPTH_ZERO)) {
                        file.refreshLocal(IResource.DEPTH_ZERO, null);
                    }

                    IOUtils.copy(file.getContents(), array);

                    String content = new String(array.toByteArray(), file.getCharset());

                    message.put("content", content);
                    message.put("type", "file");
                } else if (resource instanceof IFolder) {
                    message.put("type", "folder");
                }

                messagingConnector.send("getResourceResponse", message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void getClasspathResource(JSONObject request) {
        try {
            final int callbackID = request.getInt("callback_id");
            final String sender = request.getString("requestSenderID");
            final String projectName = request.getString("project");
            final String resourcePath = request.getString("resource");
            final String username = request.getString("username");

            ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null) {
                String typeName = resourcePath.substring("classpath:/".length());
                if (typeName.endsWith(".class")) {
                    typeName = typeName.substring(0, typeName.length() - ".class".length());
                }
                typeName = typeName.replace('/', '.');

                IJavaProject javaProject = JavaCore.create(connectedProject.getProject());
                if (javaProject != null) {
                    IType type = javaProject.findType(typeName);
                    IClassFile classFile = type.getClassFile();
                    if (classFile != null && classFile.getSourceRange() != null) {

                        JSONObject message = new JSONObject();
                        message.put("callback_id", callbackID);
                        message.put("requestSenderID", sender);
                        message.put("username", this.username);
                        message.put("project", projectName);
                        message.put("resource", resourcePath);
                        message.put("readonly", true);

                        String content = classFile.getSource();

                        message.put("content", content);
                        message.put("type", "file");

                        messagingConnector.send("getResourceResponse", message);
                    }
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (JavaModelException e) {
            e.printStackTrace();
        }
    }

    public void updateResource(JSONObject request) {
        try {
            final String username = request.getString("username");
            final String projectName = request.getString("project");
            final String resourcePath = request.getString("resource");
            final long updateTimestamp = request.getLong("timestamp");
            final String updateHash = request.optString("hash");

            ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null) {
                IProject project = connectedProject.getProject();
                IResource resource = project.findMember(resourcePath);

                if (resource != null && resource instanceof IFile) {
                    String localHash = connectedProject.getHash(resourcePath);
                    long localTimestamp = connectedProject.getTimestamp(resourcePath);

                    if (localHash != null && !localHash.equals(updateHash) && localTimestamp < updateTimestamp) {
                        JSONObject message = new JSONObject();
                        message.put("callback_id", GET_RESOURCE_CALLBACK);
                        message.put("username", this.username);
                        message.put("project", projectName);
                        message.put("resource", resourcePath);
                        message.put("timestamp", updateTimestamp);
                        message.put("hash", updateHash);

                        messagingConnector.send("getResourceRequest", message);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void createResource(JSONObject request) {
        try {
            final String username = request.getString("username");
            final String projectName = request.getString("project");
            final String resourcePath = request.getString("resource");
            final long updateTimestamp = request.getLong("timestamp");
            final String updateHash = request.optString("hash");
            final String type = request.optString("type");

            ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null) {
                IProject project = connectedProject.getProject();
                IResource resource = project.findMember(resourcePath);

                if (resource == null) {
                    if ("folder".equals(type)) {
                        IFolder newFolder = project.getFolder(resourcePath);

                        connectedProject.setHash(resourcePath, updateHash);
                        connectedProject.setTimestamp(resourcePath, updateTimestamp);

                        newFolder.create(true, true, null);
                        newFolder.setLocalTimeStamp(updateTimestamp);
                    } else if ("file".equals(type)) {
                        JSONObject message = new JSONObject();
                        message.put("callback_id", GET_RESOURCE_CALLBACK);
                        message.put("username", this.username);
                        message.put("project", projectName);
                        message.put("resource", resourcePath);
                        message.put("timestamp", updateTimestamp);
                        message.put("hash", updateHash);

                        messagingConnector.send("getResourceRequest", message);
                    }
                } else {
                    // TODO
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void deleteResource(JSONObject request) {
        try {
            final String username = request.getString("username");
            final String projectName = request.getString("project");
            final String resourcePath = request.getString("resource");
            final long deletedTimestamp = request.getLong("timestamp");

            ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null) {
                IProject project = connectedProject.getProject();
                IResource resource = project.findMember(resourcePath);

                if (resource != null && resource.exists()
                        && (resource instanceof IFile || resource instanceof IFolder)) {
                    long localTimestamp = connectedProject.getTimestamp(resourcePath);

                    if (localTimestamp < deletedTimestamp) {
                        resource.delete(true, null);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void getResourceResponse(JSONObject response) {
        try {
            final String username = response.getString("username");
            final String projectName = response.getString("project");
            final String resourcePath = response.getString("resource");
            final long updateTimestamp = response.getLong("timestamp");
            final String updateHash = response.getString("hash");

            ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null) {
                boolean stored = false;

                IProject project = connectedProject.getProject();
                IResource resource = project.findMember(resourcePath);

                if (resource != null) {
                    if (resource instanceof IFile) {
                        String localHash = connectedProject.getHash(resourcePath);
                        long localTimestamp = connectedProject.getTimestamp(resourcePath);

                        if (localHash != null && !localHash.equals(updateHash)
                                && localTimestamp < updateTimestamp) {
                            IFile file = (IFile) resource;
                            String newResourceContent = response.getString("content");

                            connectedProject.setTimestamp(resourcePath, updateTimestamp);
                            connectedProject.setHash(resourcePath, updateHash);

                            file.setContents(new ByteArrayInputStream(newResourceContent.getBytes()), true, true,
                                    null);
                            file.setLocalTimeStamp(updateTimestamp);
                            stored = true;
                        }
                    }
                } else {
                    IFile newFile = project.getFile(resourcePath);
                    String newResourceContent = response.getString("content");

                    connectedProject.setHash(resourcePath, updateHash);
                    connectedProject.setTimestamp(resourcePath, updateTimestamp);

                    newFile.create(new ByteArrayInputStream(newResourceContent.getBytes()), true, null);
                    newFile.setLocalTimeStamp(updateTimestamp);
                    stored = true;
                }

                if (stored) {
                    JSONObject message = new JSONObject();
                    message.put("username", this.username);
                    message.put("project", connectedProject.getName());
                    message.put("resource", resourcePath);
                    message.put("timestamp", updateTimestamp);
                    message.put("hash", updateHash);
                    messagingConnector.send("resourceStored", message);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void getMetadata(JSONObject request) {
        try {
            final String username = request.getString("username");
            final int callbackID = request.getInt("callback_id");
            final String sender = request.getString("requestSenderID");
            final String projectName = request.getString("project");
            final String resourcePath = request.getString("resource");

            ConnectedProject connectedProject = this.syncedProjects.get(projectName);
            if (this.username.equals(username) && connectedProject != null) {
                IProject project = connectedProject.getProject();
                IResource resource = project.findMember(resourcePath);

                JSONObject message = new JSONObject();
                message.put("callback_id", callbackID);
                message.put("requestSenderID", sender);
                message.put("username", this.username);
                message.put("project", projectName);
                message.put("resource", resourcePath);
                message.put("type", "marker");

                IMarker[] markers = resource.findMarkers(null, true, IResource.DEPTH_INFINITE);
                String markerJSON = toJSON(markers);
                JSONArray content = new JSONArray(markerJSON);
                message.put("metadata", content);

                messagingConnector.send("getMetadataResponse", message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void resourceChanged(IResourceDelta delta) {
        IProject project = delta.getResource().getProject();
        if (project != null) {
            if (isConnected(project)) {
                reactToResourceChange(delta);
            }
        }
    }

    public void metadataChanged(IResourceDelta delta) {
        IProject project = delta.getResource().getProject();
        IMarkerDelta[] markerDeltas = delta.getMarkerDeltas();
        if (project != null && isConnected(project) && markerDeltas != null && markerDeltas.length > 0) {
            sendMetadataUpdate(delta.getResource());
        }
    }

    public void reactToResourceChange(IResourceDelta delta) {
        IResource resource = delta.getResource();

        if (resource != null && resource.isDerived(IResource.CHECK_ANCESTORS)) {
            return;
        }

        switch (delta.getKind()) {
        case IResourceDelta.ADDED:
            reactOnResourceAdded(resource);
            break;
        case IResourceDelta.REMOVED:
            reactOnResourceRemoved(resource);
            break;
        case IResourceDelta.CHANGED:
            reactOnResourceChange(resource);
            break;
        }
    }

    protected void reactOnResourceAdded(IResource resource) {
        try {
            ConnectedProject connectedProject = this.syncedProjects.get(resource.getProject().getName());

            String resourcePath = resource.getProjectRelativePath().toString();
            long timestamp = resource.getLocalTimeStamp();
            String hash = "0";
            String type = null;

            connectedProject.setTimestamp(resourcePath, timestamp);

            if (resource instanceof IFile) {
                try {
                    IFile file = (IFile) resource;
                    hash = DigestUtils.shaHex(file.getContents());
                    type = "file";
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else if (resource instanceof IFolder) {
                type = "folder";
            }

            connectedProject.setHash(resourcePath, hash);

            JSONObject createdMessage = new JSONObject();
            createdMessage.put("username", this.username);
            createdMessage.put("project", connectedProject.getName());
            createdMessage.put("resource", resourcePath);
            createdMessage.put("timestamp", timestamp);
            createdMessage.put("hash", hash);
            createdMessage.put("type", type);
            messagingConnector.send("resourceCreated", createdMessage);

            JSONObject storedMessage = new JSONObject();
            storedMessage.put("username", this.username);
            storedMessage.put("project", connectedProject.getName());
            storedMessage.put("resource", resourcePath);
            storedMessage.put("timestamp", timestamp);
            storedMessage.put("hash", hash);
            messagingConnector.send("resourceStored", storedMessage);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void reactOnResourceRemoved(IResource resource) {
        if (resource instanceof IProject) {
            this.removeProject((IProject) resource);
        } else if (!resource.isDerived() && (resource instanceof IFile || resource instanceof IFolder)) {
            ConnectedProject connectedProject = this.syncedProjects.get(resource.getProject().getName());
            String resourcePath = resource.getProjectRelativePath().toString();
            long deletedTimestamp = System.currentTimeMillis();

            try {
                JSONObject message = new JSONObject();
                message.put("username", this.username);
                message.put("project", connectedProject.getName());
                message.put("resource", resourcePath);
                message.put("timestamp", deletedTimestamp);

                messagingConnector.send("resourceDeleted", message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    protected void reactOnResourceChange(IResource resource) {
        if (resource != null && resource instanceof IFile) {
            IFile file = (IFile) resource;

            ConnectedProject connectedProject = this.syncedProjects.get(file.getProject().getName());
            String resourcePath = resource.getProjectRelativePath().toString();

            try {

                long changeTimestamp = file.getLocalTimeStamp();
                if (changeTimestamp > connectedProject.getTimestamp(resourcePath)) {
                    String changeHash = DigestUtils.shaHex(file.getContents());
                    if (!changeHash.equals(connectedProject.getHash(resourcePath))) {

                        connectedProject.setTimestamp(resourcePath, changeTimestamp);
                        connectedProject.setHash(resourcePath, changeHash);

                        JSONObject changedMessage = new JSONObject();
                        changedMessage.put("username", this.username);
                        changedMessage.put("project", connectedProject.getName());
                        changedMessage.put("resource", resourcePath);
                        changedMessage.put("timestamp", changeTimestamp);
                        changedMessage.put("hash", changeHash);
                        messagingConnector.send("resourceChanged", changedMessage);

                        JSONObject storedMessage = new JSONObject();
                        storedMessage.put("username", this.username);
                        storedMessage.put("project", connectedProject.getName());
                        storedMessage.put("resource", resourcePath);
                        storedMessage.put("timestamp", changeTimestamp);
                        storedMessage.put("hash", changeHash);
                        messagingConnector.send("resourceStored", storedMessage);

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void sendMetadataUpdate(IResource resource) {
        try {
            String project = resource.getProject().getName();
            String resourcePath = resource.getProjectRelativePath().toString();

            JSONObject message = new JSONObject();
            message.put("username", this.username);
            message.put("project", project);
            message.put("resource", resourcePath);
            message.put("type", "marker");

            IMarker[] markers = resource.findMarkers(null, true, IResource.DEPTH_INFINITE);
            String markerJSON = toJSON(markers);
            JSONArray content = new JSONArray(markerJSON);
            message.put("metadata", content);

            messagingConnector.send("metadataChanged", message);
        } catch (Exception e) {

        }
    }

    public String toJSON(IMarker[] markers) {
        StringBuilder result = new StringBuilder();
        boolean flag = false;
        result.append("[");
        for (IMarker m : markers) {
            if (flag) {
                result.append(",");
            }

            result.append("{");
            result.append("\"description\":" + JSONObject.quote(m.getAttribute("message", "")));
            result.append(",\"line\":" + m.getAttribute("lineNumber", 0));
            result.append(",\"severity\":\""
                    + (m.getAttribute("severity", IMarker.SEVERITY_WARNING) == IMarker.SEVERITY_ERROR ? "error"
                            : "warning")
                    + "\"");
            result.append(",\"start\":" + m.getAttribute("charStart", 0));
            result.append(",\"end\":" + m.getAttribute("charEnd", 0));
            result.append("}");

            flag = true;
        }
        result.append("]");
        return result.toString();
    }

    public void addRepositoryListener(IRepositoryListener listener) {
        this.repositoryListeners.add(listener);
    }

    public void removeRepositoryListener(IRepositoryListener listener) {
        this.repositoryListeners.remove(listener);
    }

    protected void notifyProjectConnected(IProject project) {
        for (IRepositoryListener listener : this.repositoryListeners) {
            listener.projectConnected(project);
        }
    }

    protected void notifyProjectDisonnected(IProject project) {
        for (IRepositoryListener listener : this.repositoryListeners) {
            listener.projectDisconnected(project);
        }
    }

}