/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.resources.impl;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.ide.api.resources.Container;
import org.eclipse.che.ide.api.resources.File;
import org.eclipse.che.ide.api.resources.Folder;
import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.api.resources.Resource;
import org.eclipse.che.ide.api.resources.marker.Marker;
import org.eclipse.che.ide.resource.Path;
import org.eclipse.che.ide.util.Arrays;
import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.of;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.System.arraycopy;
import static java.util.Arrays.copyOf;
import static org.eclipse.che.ide.api.resources.marker.Marker.CREATED;
import static org.eclipse.che.ide.api.resources.marker.Marker.REMOVED;
import static org.eclipse.che.ide.api.resources.marker.Marker.UPDATED;
/**
* Default implementation of the {@code Resource}.
*
* @author Vlad Zhukovskyi
* @see Resource
* @since 4.4.0
*/
@Beta
abstract class ResourceImpl implements Resource {
protected final ResourceManager resourceManager;
protected final Path path;
protected Marker[] markers = new Marker[0];
protected ResourceImpl(Path path, ResourceManager resourceManager) {
this.path = checkNotNull(path.removeTrailingSeparator(), "Null path occurred");
this.resourceManager = checkNotNull(resourceManager, "Null project manager occurred");
}
/** {@inheritDoc} */
@Override
public boolean isFile() {
return getResourceType() == FILE;
}
@Override
public File asFile() {
checkState(isFile(), "Current resource is not a file");
return (File)this;
}
/** {@inheritDoc} */
@Override
public boolean isFolder() {
return getResourceType() == FOLDER;
}
@Override
public Folder asFolder() {
checkState(isFolder(), "Current resource is not a folder");
return (Folder)this;
}
/** {@inheritDoc} */
@Override
public boolean isProject() {
return getResourceType() == PROJECT;
}
@Override
public Project asProject() {
checkState(isProject(), "Current resource is not a project");
return (Project)this;
}
/** {@inheritDoc} */
@Override
public Promise<Resource> copy(Path destination) {
return copy(destination, false);
}
/** {@inheritDoc} */
@Override
public Promise<Resource> copy(Path destination, boolean force) {
return resourceManager.copy(this, destination, force);
}
/** {@inheritDoc} */
@Override
public Promise<Resource> move(Path destination) {
return move(destination, false);
}
/** {@inheritDoc} */
@Override
public Promise<Resource> move(Path destination, boolean force) {
return resourceManager.move(this, destination, force);
}
/** {@inheritDoc} */
@Override
public Promise<Void> delete() {
return resourceManager.delete(this);
}
/** {@inheritDoc} */
@Override
public Path getLocation() {
return path;
}
/** {@inheritDoc} */
@Override
public Container getParent() {
final Optional<Container> parent = resourceManager.parentOf(this);
return parent.isPresent() ? parent.get() : null;
}
/** {@inheritDoc} */
@Override
public Optional<Project> getRelatedProject() {
if (this instanceof Project) {
return of((Project)this);
}
Container optionalParent = getParent();
if (optionalParent == null) {
return absent();
}
Container parent = optionalParent;
while (!(parent instanceof Project)) {
optionalParent = parent.getParent();
if (optionalParent == null) {
return absent();
}
parent = optionalParent;
}
return of((Project)parent);
}
@Override
public Project getProject() {
final Optional<Project> project = getRelatedProject();
return project.isPresent() ? project.get() : null;
}
/** {@inheritDoc} */
@Override
public abstract int getResourceType();
/** {@inheritDoc} */
@Override
public String getName() {
return path.isRoot() ? "Workspace" : path.lastSegment();
}
/** {@inheritDoc} */
@Override
public String getURL() {
return resourceManager.getUrl(this);
}
/** {@inheritDoc} */
@Override
public Optional<Marker> getMarker(String type) {
checkArgument(!isNullOrEmpty(type), "Invalid marker type occurred");
if (markers.length == 0) {
return absent();
}
for (Marker marker : markers) {
if (marker.getType().equals(type)) {
return of(marker);
}
}
return absent();
}
/** {@inheritDoc} */
@Override
public Marker[] getMarkers() {
return markers;
}
/** {@inheritDoc} */
@Override
public void addMarker(Marker marker) {
checkArgument(marker != null, "Null marker occurred");
for (int i = 0; i < markers.length; i++) {
if (markers[i].getType().equals(marker.getType())) {
markers[i] = marker;
resourceManager.notifyMarkerChanged(this, marker, UPDATED);
return;
}
}
final int index = markers.length;
markers = copyOf(markers, index + 1);
markers[index] = marker;
resourceManager.notifyMarkerChanged(this, marker, CREATED);
}
/** {@inheritDoc} */
@Override
public boolean deleteMarker(String type) {
checkArgument(!isNullOrEmpty(type), "Invalid marker type occurred");
int size = markers.length;
int index = -1;
for (int i = 0; i < markers.length; i++) {
if (markers[i].getType().equals(type)) {
index = i;
resourceManager.notifyMarkerChanged(this, markers[i], REMOVED);
break;
}
}
if (index == -1) {
return false;
}
final int numMoved = markers.length - index - 1;
if (numMoved > 0) {
arraycopy(markers, index + 1, markers, index, numMoved);
}
markers = copyOf(markers, --size);
return true;
}
/** {@inheritDoc} */
@Override
public boolean deleteAllMarkers() {
if (Arrays.isNullOrEmpty(markers)) {
return false;
}
markers = new Marker[0];
return true;
}
/** {@inheritDoc} */
@Override
public Optional<Resource> getParentWithMarker(String type) {
checkArgument(!isNullOrEmpty(type), "Invalid marker type occurred");
if (getMarker(type).isPresent()) {
return Optional.<Resource>of(this);
}
Container optParent = getParent();
while (optParent != null) {
Container parent = optParent;
final Optional<Marker> marker = parent.getMarker(type);
if (marker.isPresent()) {
return Optional.<Resource>of(parent);
}
optParent = parent.getParent();
}
return absent();
}
/** {@inheritDoc} */
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Resource)) {
return false;
}
Resource resource = (Resource)o;
return getResourceType() == resource.getResourceType() && getLocation().equals(resource.getLocation());
}
/** {@inheritDoc} */
@Override
public int hashCode() {
return Objects.hashCode(getResourceType(), getLocation().toString());
}
/** {@inheritDoc} */
@Override
public int compareTo(Resource o) {
return getLocation().toString().compareTo(o.getLocation().toString());
}
/** {@inheritDoc} */
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("path", path)
.add("resource", getResourceType())
.toString();
}
}