/*******************************************************************************
* Copyright (c) 2009 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
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.debug.core.pathmapper;
import java.io.File;
import java.util.*;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.php.internal.core.util.preferences.IXMLPreferencesStorable;
import org.eclipse.php.internal.debug.core.pathmapper.PathEntry.Type;
import org.eclipse.php.internal.debug.core.pathmapper.PathMapper.Mapping.MappingSource;
public class PathMapper implements IXMLPreferencesStorable {
private Map<VirtualPath, VirtualPath> remoteToLocalMap;
private Map<VirtualPath, VirtualPath> localToRemoteMap;
private Map<VirtualPath, Type> localToPathEntryType;
private Map<VirtualPath, MappingSource> localToMappingSource;
public PathMapper() {
remoteToLocalMap = new HashMap<VirtualPath, VirtualPath>();
localToRemoteMap = new HashMap<VirtualPath, VirtualPath>();
localToPathEntryType = new HashMap<VirtualPath, Type>();
localToMappingSource = new HashMap<VirtualPath, MappingSource>();
}
public synchronized void addEntry(String remoteFile, PathEntry entry, MappingSource source) {
VirtualPath remotePath = new VirtualPath(remoteFile);
VirtualPath localPath = entry.getAbstractPath().clone(); // don't break
// original
// entry
// path
// last segments must match!
if (!remotePath.getLastSegment().equalsIgnoreCase(localPath.getLastSegment())) {
return;
}
while (remotePath.getSegmentsCount() > 0 && localPath.getSegmentsCount() > 1) { // local
// path
// is
// limited
// to
// have
// at
// least
// one
// segment
if (!remotePath.getLastSegment().equalsIgnoreCase(localPath.getLastSegment())) {
break;
}
remotePath.removeLastSegment();
localPath.removeLastSegment();
}
if (!remotePath.equals(localPath)) {
remoteToLocalMap.put(remotePath, localPath);
localToRemoteMap.put(localPath, remotePath);
localToPathEntryType.put(localPath, entry.getType());
localToMappingSource.put(localPath, source);
}
}
public synchronized void addServerEntry(String remoteFile, PathEntry entry, MappingSource source) {
VirtualPath localPath = entry.getAbstractPath().clone(); // don't break
// original
// entry
// path
remoteToLocalMap.put(localPath, localPath);
localToRemoteMap.put(localPath, localPath);
localToPathEntryType.put(localPath, entry.getType());
localToMappingSource.put(localPath, source);
}
public String getRemoteFile(String localFile) {
VirtualPath path = getPath(localToRemoteMap, new VirtualPath(localFile));
if (path != null) {
return path.toString();
}
return null;
}
/**
* Returns exact mapping for the given remote path (if exists)
*
* @param remoteFile
* Remote path
* @return virtual path
*/
public VirtualPath getLocalPathMapping(VirtualPath remotePath) {
return remoteToLocalMap.get(remotePath);
}
public PathEntry getLocalFile(String remoteFile) {
VirtualPath path = getPath(remoteToLocalMap, new VirtualPath(remoteFile));
if (path != null) {
String localFile = path.toString();
Type type = getPathType(path);
if (type == Type.SERVER) {
return null;
} else if (type == Type.WORKSPACE) {
IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(localFile);
if (resource != null) {
return new PathEntry(path, type, resource.getParent());
}
} else {
File file = new File(localFile);
if (file.exists()) {
if (type == Type.INCLUDE_FOLDER || type == Type.INCLUDE_VAR) {
return new PathEntry(path, type, null);
}
return new PathEntry(path, type, file.getParentFile());
}
}
}
return null;
}
public PathEntry getServerFile(String remoteFile) {
VirtualPath tmp = new VirtualPath(remoteFile);
for (VirtualPath path : remoteToLocalMap.keySet()) {
if (localToPathEntryType.get(path) == Type.SERVER) {
if (path.isPrefixOf(tmp)) {
return new PathEntry(path, Type.SERVER, null);
}
}
}
return null;
}
protected VirtualPath getPath(Map<VirtualPath, VirtualPath> map, VirtualPath path) {
path = path.clone();
VirtualPath mapPath = null;
List<String> strippedSegments = new LinkedList<String>();
while (path.getSegmentsCount() > 0) {
mapPath = map.get(path);
if (mapPath != null) {
mapPath = mapPath.clone();
break;
}
strippedSegments.add(path.removeLastSegment());
}
// Check whether device is mapped (path contains only device):
if (mapPath == null) {
mapPath = map.get(path);
if (mapPath != null) {
mapPath = mapPath.clone();
}
}
// Append all stripped segments to the result path:
if (mapPath != null) {
ListIterator<String> i = strippedSegments.listIterator(strippedSegments.size());
while (i.hasPrevious()) {
mapPath.addLastSegment(i.previous());
}
}
return mapPath;
}
protected Type getPathType(VirtualPath path) {
path = path.clone();
while (path.getSegmentsCount() > 0) {
Type type = localToPathEntryType.get(path);
if (type != null) {
return type;
}
path.removeLastSegment();
}
return localToPathEntryType.get(path);
}
/**
* Returns contents of this path mapper
*/
public synchronized Mapping[] getMapping() {
List<Mapping> l = new ArrayList<Mapping>(localToRemoteMap.size());
Iterator<VirtualPath> i = localToRemoteMap.keySet().iterator();
while (i.hasNext()) {
VirtualPath localPath = i.next();
VirtualPath remotePath = localToRemoteMap.get(localPath);
Type type = localToPathEntryType.get(localPath);
MappingSource source = localToMappingSource.get(localPath);
l.add(new Mapping(localPath, remotePath, type, source));
}
return l.toArray(new Mapping[l.size()]);
}
/**
* Sets this path mapper contents removing any previous mappings
*/
public synchronized void setMapping(Mapping[] mappings) {
remoteToLocalMap.clear();
localToRemoteMap.clear();
localToPathEntryType.clear();
localToMappingSource.clear();
for (Mapping mapping : mappings) {
localToRemoteMap.put(mapping.localPath, mapping.remotePath);
remoteToLocalMap.put(mapping.remotePath, mapping.localPath);
localToPathEntryType.put(mapping.localPath, mapping.type);
localToMappingSource.put(mapping.localPath, mapping.source);
}
}
/**
* Adds new mapping to this mapper
*/
public synchronized void addMapping(Mapping mapping) {
localToRemoteMap.put(mapping.localPath, mapping.remotePath);
remoteToLocalMap.put(mapping.remotePath, mapping.localPath);
localToPathEntryType.put(mapping.localPath, mapping.type);
localToMappingSource.put(mapping.localPath, mapping.source);
}
/**
* Removes mapping
*/
public synchronized void removeMapping(Mapping mapping) {
localToRemoteMap.remove(mapping.localPath);
remoteToLocalMap.remove(mapping.remotePath);
localToPathEntryType.remove(mapping.localPath);
localToMappingSource.remove(mapping.localPath);
}
public static class Mapping implements Cloneable {
public enum MappingSource {
UNKNOWN(Messages.PathMapper_MappingSource_Unknown_Name), ENVIRONMENT(
Messages.PathMapper_MappingSource_Environment_Name), USER(
Messages.PathMapper_MappingSource_User_Name);
private String name;
private MappingSource(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
public VirtualPath localPath;
public VirtualPath remotePath;
public Type type;
public MappingSource source;
public Mapping() {
}
public Mapping(VirtualPath localPath, VirtualPath remotePath, Type type, MappingSource source) {
this.localPath = localPath;
this.remotePath = remotePath;
this.type = type;
this.source = source;
}
public Mapping clone() {
return new Mapping(localPath, remotePath, type, source);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Mapping other = (Mapping) obj;
if (localPath == null) {
if (other.localPath != null)
return false;
} else if (!localPath.equals(other.localPath))
return false;
if (remotePath == null) {
if (other.remotePath != null)
return false;
} else if (!remotePath.equals(other.remotePath))
return false;
if (source != other.source)
return false;
if (type != other.type)
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((localPath == null) ? 0 : localPath.hashCode());
result = prime * result + ((remotePath == null) ? 0 : remotePath.hashCode());
result = prime * result + ((source == null) ? 0 : source.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
public String toString() {
StringBuilder buf = new StringBuilder("Mapping { "); //$NON-NLS-1$
buf.append(localPath).append(", ").append(remotePath).append(", ") //$NON-NLS-1$ //$NON-NLS-2$
.append(type).append(", ").append(source.name()) //$NON-NLS-1$
.append(" }"); //$NON-NLS-1$
return buf.toString();
}
}
public synchronized void restoreFromMap(Map<String, Object> map) {
if (map == null) {
return;
}
remoteToLocalMap.clear();
localToRemoteMap.clear();
localToPathEntryType.clear();
localToMappingSource.clear();
Iterator<String> i = map.keySet().iterator();
while (i.hasNext()) {
@SuppressWarnings("unchecked")
Map<String, Object> entryMap = (Map<String, Object>) map.get(i.next());
String localStr = (String) entryMap.get("local"); //$NON-NLS-1$
String remoteStr = (String) entryMap.get("remote"); //$NON-NLS-1$
String typeStr = (String) entryMap.get("type"); //$NON-NLS-1$
String sourceStr = (String) entryMap.get("source"); //$NON-NLS-1$
if (localStr != null && remoteStr != null && typeStr != null) {
Type type = Type.valueOf(typeStr);
MappingSource source = MappingSource.UNKNOWN;
if (sourceStr != null) {
source = MappingSource.valueOf(sourceStr);
}
VirtualPath local = new VirtualPath(localStr);
VirtualPath remote = new VirtualPath(remoteStr);
remoteToLocalMap.put(remote, local);
localToRemoteMap.put(local, remote);
localToPathEntryType.put(local, type);
localToMappingSource.put(local, source);
}
}
}
public synchronized Map<String, Object> storeToMap() {
Map<String, Object> entries = new HashMap<String, Object>();
Iterator<VirtualPath> i = localToRemoteMap.keySet().iterator();
int c = 1;
while (i.hasNext()) {
Map<String, Object> entry = new HashMap<String, Object>();
VirtualPath local = i.next();
VirtualPath remote = localToRemoteMap.get(local);
Type type = localToPathEntryType.get(local);
MappingSource source = localToMappingSource.get(local);
entry.put("local", local); //$NON-NLS-1$
entry.put("remote", remote); //$NON-NLS-1$
if (type != null) {
entry.put("type", type.name()); //$NON-NLS-1$
}
if (source != null) {
entry.put("source", source.name()); //$NON-NLS-1$
}
entries.put("item" + (c++), entry); //$NON-NLS-1$
}
return entries;
}
}