blob: c2ce806e11f23669bb7b59adba9c3a9871103dd0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - Initial API and implementation
*******************************************************************************/
package org.eclipse.wst.server.core.internal;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.core.runtime.IPath;
import org.eclipse.wst.server.core.IModule;
import org.eclipse.wst.server.core.IServer;
import org.eclipse.wst.server.core.ServerUtil;
import org.eclipse.wst.server.core.model.IModuleFile;
import org.eclipse.wst.server.core.model.IModuleFolder;
import org.eclipse.wst.server.core.model.IModuleResource;
import org.eclipse.wst.server.core.model.IModuleResourceDelta;
/**
* Helper to obtain and store the publishing information (what files
* were published and when) for a single server.
*/
public class ServerPublishInfo {
private static final String VERSION = "version";
protected IPath path;
// map of module ids to ModulePublishInfo
protected Map<String, ModulePublishInfo> modulePublishInfo;
/**
* ServerPublishInfo constructor comment.
*/
protected ServerPublishInfo(IPath path) {
super();
this.path = path;
modulePublishInfo = new HashMap<String, ModulePublishInfo>();
load();
}
private String getKey(IModule[] module) {
StringBuffer sb = new StringBuffer();
if (module != null) {
int size = module.length;
for (int i = 0; i < size; i++) {
if (i != 0)
sb.append("#");
if (module[i] != null)
sb.append(module[i].getId());
else
sb.append("null");
}
}
return sb.toString();
}
private String getKey(String moduleId) {
return moduleId;
}
private IModule[] getModule(String moduleId) {
if (moduleId == null || moduleId.length() == 0)
return new IModule[0];
List<IModule> list = new ArrayList<IModule>();
StringTokenizer st = new StringTokenizer(moduleId, "#");
while (st.hasMoreTokens()) {
String mid = st.nextToken();
if (mid != null && mid.length() > 0) {
IModule m = ServerUtil.getModule(mid);
if (m == null)
return null;
list.add(m);
}
}
IModule[] modules = new IModule[list.size()];
list.toArray(modules);
return modules;
}
public boolean hasModulePublishInfo(IModule[] module) {
String key = getKey(module);
synchronized (modulePublishInfo) {
return modulePublishInfo.containsKey(key);
}
}
/*public void removeModulePublishInfo(IModule[] module) {
String key = getKey(module);
modulePublishInfo.remove(key);
save();
}*/
/**
*
* Note: save() must be called manually after making this call.
*
* @param moduleList
* @deprecated Use removeDeletedModulePublishInfo(Server, List) instead
*/
public void removeDeletedModulePublishInfo(List moduleList) {
removeDeletedModulePublishInfo(null, moduleList);
}
/**
* Removes successfully deleted modules from the next publish.
* Note: save() must be called manually after making this call.
*
* @param server a server
* @param moduleList the modules currently on the server
*/
public void removeDeletedModulePublishInfo(Server server, List moduleList) {
int size = moduleList.size();
List<String> removed = new ArrayList<String>();
synchronized (modulePublishInfo) {
Iterator iterator = modulePublishInfo.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
boolean found = false;
for (int i = 0; i < size; i++) {
IModule[] module = (IModule[]) moduleList.get(i);
String key2 = getKey(module);
if (key != null && key.equals(key2))
found = true;
}
if (server != null) {
try {
Integer in = server.modulePublishState.get(key);
if (in != null && in.intValue() != IServer.PUBLISH_STATE_NONE)
found = true;
} catch (Exception e) {
// ignore
}
}
if (!found)
removed.add(key);
}
iterator = removed.iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
modulePublishInfo.remove(key);
}
}
}
/**
* Return the publish state.
*/
protected ModulePublishInfo getModulePublishInfo(IModule[] module) {
String key = getKey(module);
// check if it now exists
synchronized (modulePublishInfo) {
if (modulePublishInfo.containsKey(key))
return modulePublishInfo.get(key);
// have to create a new one
IModule mod = module[module.length - 1];
ModulePublishInfo mpi = new ModulePublishInfo(getKey(module), mod.getName(), mod.getModuleType());
modulePublishInfo.put(key, mpi);
return mpi;
}
}
public void addRemovedModules(List<IModule[]> moduleList) {
int size = moduleList.size();
List<ModulePublishInfo> removed = new ArrayList<ModulePublishInfo>();
synchronized (modulePublishInfo) {
Iterator iterator = modulePublishInfo.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
boolean found = false;
for (int i = 0; i < size; i++) {
IModule[] module = moduleList.get(i);
String key2 = getKey(module);
if (key != null && key.equals(key2))
found = true;
}
if (!found) {
ModulePublishInfo mpi = modulePublishInfo.get(key);
removed.add(mpi);
}
}
iterator = removed.iterator();
while (iterator.hasNext()) {
ModulePublishInfo mpi = (ModulePublishInfo) iterator.next();
IModule[] module2 = getModule(mpi.getModuleId());
if (module2 == null || module2.length == 0) {
String moduleId = mpi.getModuleId();
if (moduleId != null) {
String[] ids = getModuleIds(moduleId);
int depth = ids.length;
module2 = new IModule[depth];
String s = "";
for (int i = 0; i < depth; i++) {
s += ids[i];
if (i == depth - 1)
module2[i] = mpi.getDeletedModule();
else {
ModulePublishInfo mpi2 = modulePublishInfo.get(s);
if (mpi2 != null)
module2[i] = mpi2.getDeletedModule();
}
s += "#";
}
}
}
if (module2 != null && module2.length > 0)
moduleList.add(module2);
}
}
}
/**
* Parse a combined module id string into the individual module ids
* @param moduleId
* @return an array of module ids
*/
private String[] getModuleIds(String moduleId) {
StringTokenizer st = new StringTokenizer(moduleId, "#");
List<String> list = new ArrayList<String>(2);
while (st.hasMoreTokens()) {
list.add(st.nextToken());
}
String[] s = new String[list.size()];
list.toArray(s);
return s;
}
/**
*
*/
public void load() {
String filename = path.toOSString();
if (new File(filename).exists()) {
Trace.trace(Trace.FINEST, "Loading publish info from " + filename);
DataInputStream in = null;
try {
in = new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
in.readByte();
in.readByte();
// version
int ver = in.readByte();
if (ver <= 1) {
int size = in.readInt();
for (int i = 0; i < size; i++) {
ModulePublishInfo mpi = new ModulePublishInfo(in);
modulePublishInfo.put(getKey(mpi.getModuleId()), mpi);
}
return;
}
} catch (Exception e) {
Trace.trace(Trace.WARNING, "Could not load publish information", e);
}
}
filename = filename.substring(0, filename.length() - 3) + "xml";
if (new File(filename).exists()) {
Trace.trace(Trace.FINEST, "Loading publish info from old format " + filename);
try {
IMemento memento2 = XMLMemento.loadMemento(filename);
Float f = memento2.getFloat(VERSION);
if (f != null && f.floatValue() >= 3)
return;
IMemento[] children = memento2.getChildren("module");
int size = children.length;
for (int i = 0; i < size; i++) {
ModulePublishInfo mpi = new ModulePublishInfo(children[i]);
modulePublishInfo.put(getKey(mpi.getModuleId()), mpi);
}
} catch (Exception e) {
Trace.trace(Trace.WARNING, "Could not load publish information", e);
}
}
}
/**
*
*/
public void save() {
String filename = path.toOSString();
Trace.trace(Trace.FINEST, "Saving publish info to " + filename);
DataOutputStream out = null;
try {
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(filename)));
out.writeByte(14);
out.writeByte(14);
// version
out.writeByte(1);
synchronized (modulePublishInfo) {
out.writeInt(modulePublishInfo.keySet().size());
Iterator iterator = modulePublishInfo.keySet().iterator();
while (iterator.hasNext()) {
String controlRef = (String) iterator.next();
ModulePublishInfo mpi = modulePublishInfo.get(controlRef);
mpi.save(out);
}
}
} catch (Exception e) {
Trace.trace(Trace.SEVERE, "Could not save publish information", e);
} finally {
try {
if (out != null)
out.close();
} catch (Exception e) {
// ignore
}
}
// remove old file
filename = filename.substring(0, filename.length() - 3) + "xml";
File f = new File(filename);
if (f.exists())
f.delete();
}
/**
*
* Note: save() must be called manually after making this call.
* @param module
*/
public void fill(IModule[] module) {
ModulePublishInfo mpi = getModulePublishInfo(module);
mpi.fill(module);
}
protected IModuleResourceDelta[] getDelta(IModule[] module) {
if (module == null)
return new IModuleResourceDelta[0];
return getModulePublishInfo(module).getDelta(module);
}
protected IModuleResource[] getResources(IModule[] module) {
if (module == null)
return new IModuleResource[0];
return getModulePublishInfo(module).getModuleResources(module);
}
protected static IModuleResourceDelta[] getDelta(IModuleResource[] original, IModuleResource[] current) {
if (original == null || current == null)
return new IModuleResourceDelta[0];
List<ModuleResourceDelta> list = new ArrayList<ModuleResourceDelta>();
int size = original.length;
int size2 = current.length;
Map<IModuleResource, IModuleResource> originalMap = new HashMap<IModuleResource, IModuleResource>(size);
for (int i = 0; i < size; i++)
originalMap.put(original[i], original[i]);
// added and changed resources
for (int i = 0; i < size2; i++) {
IModuleResource old = originalMap.remove(current[i]);
if (old == null) {
ModuleResourceDelta delta = new ModuleResourceDelta(current[i], IModuleResourceDelta.ADDED);
if (current[i] instanceof IModuleFolder) {
IModuleFolder currentFolder = (IModuleFolder) current[i];
delta.setChildren(getDeltaTree(currentFolder.members(), IModuleResourceDelta.ADDED));
}
list.add(delta);
} else {
if (current[i] instanceof IModuleFile) {
// include files only if the modification stamp has changed
IModuleFile mf1 = (IModuleFile) old;
IModuleFile mf2 = (IModuleFile) current[i];
if (mf1.getModificationStamp() != mf2.getModificationStamp()) {
list.add(new ModuleResourceDelta(current[i], IModuleResourceDelta.CHANGED));
}
} else {
// include folders only if their contents have changed
IModuleFolder mf1 = (IModuleFolder) old;
IModuleFolder mf2 = (IModuleFolder) current[i];
IModuleResourceDelta[] mrdc = getDelta(mf1.members(), mf2.members());
if (mrdc.length > 0) {
ModuleResourceDelta mrd = new ModuleResourceDelta(current[i], IModuleResourceDelta.NO_CHANGE);
mrd.setChildren(mrdc);
list.add(mrd);
}
}
}
}
// removed resources
for (int i = 0; i < size; i++) {
if (originalMap.containsKey(original[i])) {
ModuleResourceDelta delta = new ModuleResourceDelta(original[i], IModuleResourceDelta.REMOVED);
if (original[i] instanceof IModuleFolder) {
IModuleFolder removedFolder = (IModuleFolder) original[i];
delta.setChildren(getDeltaTree(removedFolder.members(), IModuleResourceDelta.REMOVED));
}
list.add(delta);
}
}
return list.toArray(new IModuleResourceDelta[list.size()]);
}
protected boolean hasDelta(IModule[] module) {
if (module == null)
return false;
return hasModulePublishInfo(module)
&& getModulePublishInfo(module).hasDelta(module);
}
protected static boolean hasDelta(IModuleResource[] original, IModuleResource[] current) {
if (original == null || current == null)
return false;
int size = original.length;
int size2 = current.length;
Map<IModuleResource, IModuleResource> originalMap = new HashMap<IModuleResource, IModuleResource>(size);
for (int i = 0; i < size; i++)
originalMap.put(original[i], original[i]);
// added and changed resources
for (int i = 0; i < size2; i++) {
IModuleResource old = originalMap.remove(current[i]);
if (old == null)
return true;
if (current[i] instanceof IModuleFile) {
// include files only if the modification stamp has changed
IModuleFile mf1 = (IModuleFile) old;
IModuleFile mf2 = (IModuleFile) current[i];
if (mf1.getModificationStamp() != mf2.getModificationStamp())
return true;
} else {
// include folders only if their contents have changed
IModuleFolder mf1 = (IModuleFolder) old;
IModuleFolder mf2 = (IModuleFolder) current[i];
if (hasDelta(mf1.members(), mf2.members()))
return true;
}
}
// removed resources
return !originalMap.isEmpty();
}
/**
* Create a resource delta for an entire tree.
*/
private static IModuleResourceDelta[] getDeltaTree(IModuleResource[] resources, int kind) {
if (resources == null)
return new IModuleResourceDelta[0];
List<ModuleResourceDelta> list = new ArrayList<ModuleResourceDelta>();
// look for duplicates
int size = resources.length;
for (int i = 0; i < size; i++) {
ModuleResourceDelta mrd = new ModuleResourceDelta(resources[i], kind);
if (resources[i] instanceof IModuleFolder) {
IModuleFolder mf = (IModuleFolder) resources[i];
mrd.setChildren(getDeltaTree(mf.members(), kind));
}
list.add(mrd);
}
return list.toArray(new IModuleResourceDelta[list.size()]);
}
/**
* Returns true if the list of modules being published does not match the previous
* list of published modules.
*
* This method should compare the modules. For now, comparing the size is fine.
*
* @param modules a list of modules
* @return <code>true</code> if the structure of published modules has changed, or
* <code>false</code> otherwise
*/
protected boolean hasStructureChanged(List modules) {
synchronized (modulePublishInfo) {
return modules.size() != modulePublishInfo.keySet().size();
}
}
/**
* Fill the module cache.
*/
public void startCaching() {
synchronized (modulePublishInfo) {
Iterator iterator = modulePublishInfo.values().iterator();
while (iterator.hasNext()) {
ModulePublishInfo mpi = (ModulePublishInfo) iterator.next();
mpi.startCaching();
}
}
}
/**
* Clears all caches of current module resources and deltas.
*/
public void clearCache() {
synchronized (modulePublishInfo) {
Iterator iterator = modulePublishInfo.values().iterator();
while (iterator.hasNext()) {
ModulePublishInfo mpi = (ModulePublishInfo) iterator.next();
mpi.clearCache();
}
}
}
}