/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.core;
import java.util.ArrayList;
import java.util.List;
import javax.jcr.RepositoryException;
import org.apache.jackrabbit.core.session.SessionContext;
import org.apache.jackrabbit.core.session.SessionOperation;
import org.apache.jackrabbit.core.state.ItemState;
import org.apache.jackrabbit.core.state.SessionItemStateManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ItemRefreshOperation implements SessionOperation<Object> {
/**
* Logger instance.
*/
private static final Logger log =
LoggerFactory.getLogger(ItemRefreshOperation.class);
private final ItemState state;
private final boolean keepChanges;
public ItemRefreshOperation(ItemState state, boolean keepChanges) {
this.state = state;
this.keepChanges = keepChanges;
}
public Object perform(SessionContext context) throws RepositoryException {
if (keepChanges) {
// FIXME When keepChanges is true, should reset Item#status field
// to STATUS_NORMAL of all descendant non-transient instances;
// maybe also have to reset stale ItemState instances
return this;
}
SessionItemStateManager stateMgr = context.getItemStateManager();
// Optimisation for the root node
if (state.getParentId() == null) {
stateMgr.disposeAllTransientItemStates();
return this;
}
// list of transient items that should be discarded
List<ItemState> transientStates = new ArrayList<ItemState>();
// check status of this item's state
if (state.isTransient()) {
switch (state.getStatus()) {
case ItemState.STATUS_STALE_DESTROYED:
// add this item's state to the list
transientStates.add(state);
break;
case ItemState.STATUS_EXISTING_MODIFIED:
if (!state.getParentId().equals(
state.getOverlayedState().getParentId())) {
throw new RepositoryException(
"Cannot refresh a moved item,"
+ " try refreshing the parent: " + this);
}
transientStates.add(state);
break;
case ItemState.STATUS_NEW:
throw new RepositoryException(
"Cannot refresh a new item: " + this);
default:
// log and ignore
log.warn("Unexpected item state status {} of {}",
state.getStatus(), this);
break;
}
}
if (state.isNode()) {
// build list of 'new', 'modified' or 'stale' descendants
for (ItemState transientState
: stateMgr.getDescendantTransientItemStates(state.getId())) {
switch (transientState.getStatus()) {
case ItemState.STATUS_STALE_DESTROYED:
case ItemState.STATUS_NEW:
case ItemState.STATUS_EXISTING_MODIFIED:
// add new or modified state to the list
transientStates.add(transientState);
break;
default:
// log and ignore
log.debug("unexpected state status ({})",
transientState.getStatus());
break;
}
}
}
// process list of 'new', 'modified' or 'stale' transient states
for (ItemState transientState : transientStates) {
// dispose the transient state, it is no longer used;
// this will indirectly (through stateDiscarded listener method)
// either restore or permanently invalidate the wrapping Item instances
stateMgr.disposeTransientItemState(transientState);
}
if (state.isNode()) {
// discard all transient descendants in the attic (i.e. those marked
// as 'removed'); this will resurrect the removed items
for (ItemState descendant
: stateMgr.getDescendantTransientItemStatesInAttic(state.getId())) {
// dispose the transient state; this will indirectly
// (through stateDiscarded listener method) resurrect
// the wrapping Item instances
stateMgr.disposeTransientItemStateInAttic(descendant);
}
}
return this;
}
//--------------------------------------------------------------< Object >
/**
* Returns a string representation of this operation.
*/
public String toString() {
return "item.refresh(" + keepChanges + ")";
}
}