/**
* 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.isis.viewer.wicket.ui.actionresponse;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import com.google.common.collect.Lists;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.request.IRequestHandler;
import org.apache.isis.applib.value.Blob;
import org.apache.isis.applib.value.Clob;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
import org.apache.isis.viewer.wicket.model.models.ActionModel;
import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
import org.apache.isis.viewer.wicket.model.models.ValueModel;
import org.apache.isis.viewer.wicket.model.models.VoidModel;
import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
import org.apache.isis.viewer.wicket.ui.pages.standalonecollection.StandaloneCollectionPage;
import org.apache.isis.viewer.wicket.ui.pages.value.ValuePage;
import org.apache.isis.viewer.wicket.ui.pages.voidreturn.VoidReturnPage;
public enum ActionResultResponseType {
OBJECT {
@Override
public ActionResultResponse interpretResult(final ActionModel model, final AjaxRequestTarget target, final ObjectAdapter resultAdapter) {
final ObjectAdapter actualAdapter = determineActualAdapter(resultAdapter, model.getIsisSessionFactory());
return toEntityPage(model, actualAdapter, null);
}
@Override
public ActionResultResponse interpretResult(final ActionModel model, final ObjectAdapter targetAdapter, final ConcurrencyException ex) {
final ActionResultResponse actionResultResponse = toEntityPage(model, targetAdapter, ex);
return actionResultResponse;
}
},
COLLECTION {
@Override
public ActionResultResponse interpretResult(final ActionModel actionModel, final AjaxRequestTarget target, final ObjectAdapter resultAdapter) {
final EntityCollectionModel collectionModel = EntityCollectionModel.createStandalone(resultAdapter, actionModel.getIsisSessionFactory());
// take a copy of the actionModel, because the original can get mutated (specifically: its arguments cleared)
final ActionModel actionModelCopy = actionModel.copy();
collectionModel.setActionHint(actionModelCopy);
return ActionResultResponse.toPage(new StandaloneCollectionPage(collectionModel));
}
},
VALUE {
@Override
public ActionResultResponse interpretResult(final ActionModel model, final AjaxRequestTarget target, final ObjectAdapter resultAdapter) {
ValueModel valueModel = new ValueModel(resultAdapter);
valueModel.setActionHint(model);
final ValuePage valuePage = new ValuePage(valueModel);
return ActionResultResponse.toPage(valuePage);
}
},
VALUE_CLOB {
@Override
public ActionResultResponse interpretResult(final ActionModel model, final AjaxRequestTarget target, final ObjectAdapter resultAdapter) {
final Object value = resultAdapter.getObject();
IRequestHandler handler = ActionModel.downloadHandler(value);
return ActionResultResponse.withHandler(handler);
}
},
VALUE_BLOB {
@Override
public ActionResultResponse interpretResult(final ActionModel model, final AjaxRequestTarget target, final ObjectAdapter resultAdapter) {
final Object value = resultAdapter.getObject();
IRequestHandler handler = ActionModel.downloadHandler(value);
return ActionResultResponse.withHandler(handler);
}
},
VALUE_URL_AJAX {
@Override
public ActionResultResponse interpretResult(final ActionModel model, final AjaxRequestTarget target, final ObjectAdapter resultAdapter) {
final URL url = (URL)resultAdapter.getObject();
return ActionResultResponse.openUrlInBrowser(target, url);
}
},
VALUE_URL_NOAJAX {
@Override
public ActionResultResponse interpretResult(final ActionModel model, final AjaxRequestTarget target, final ObjectAdapter resultAdapter) {
// open URL server-side redirect
final Object value = resultAdapter.getObject();
IRequestHandler handler = ActionModel.redirectHandler(value);
return ActionResultResponse.withHandler(handler);
}
},
VOID {
@Override
public ActionResultResponse interpretResult(final ActionModel model, final AjaxRequestTarget target, final ObjectAdapter resultAdapter) {
final VoidModel voidModel = new VoidModel();
voidModel.setActionHint(model);
return ActionResultResponse.toPage(new VoidReturnPage(voidModel));
}
};
public abstract ActionResultResponse interpretResult(ActionModel model, final AjaxRequestTarget target, ObjectAdapter resultAdapter);
/**
* Only overridden for {@link ActionResultResponseType#OBJECT object}
*/
public ActionResultResponse interpretResult(ActionModel model, ObjectAdapter targetAdapter, ConcurrencyException ex) {
throw new UnsupportedOperationException("Cannot render concurrency exception for any result type other than OBJECT");
}
private static ObjectAdapter determineActualAdapter(
final ObjectAdapter resultAdapter,
final IsisSessionFactory isisSessionFactory) {
if (resultAdapter.getSpecification().isNotCollection()) {
return resultAdapter;
} else {
// will only be a single element
final List<Object> pojoList = asList(resultAdapter);
final Object pojo = pojoList.get(0);
return adapterFor(pojo, isisSessionFactory);
}
}
private static ObjectAdapter adapterFor(
final Object pojo,
final IsisSessionFactory isisSessionFactory) {
return isisSessionFactory.getCurrentSession().getPersistenceSession().adapterFor(pojo);
}
private static ActionResultResponse toEntityPage(final ActionModel model, final ObjectAdapter actualAdapter, final ConcurrencyException exIfAny) {
// this will not preserve the URL (because pageParameters are not copied over)
// but trying to preserve them seems to cause the 302 redirect to be swallowed somehow
final EntityPage entityPage =
// disabling concurrency checking after the layout XML (grid) feature
// was throwing an exception when rebuild grid after invoking action
// not certain why that would be the case, but think it should be
// safe to simply disable while recreating the page to re-render back to user.
AdapterManager.ConcurrencyChecking.executeWithConcurrencyCheckingDisabled(
new Callable<EntityPage>() {
@Override public EntityPage call() throws Exception {
return new EntityPage(actualAdapter, exIfAny);
}
}
);
return ActionResultResponse.toPage(entityPage);
}
// //////////////////////////////////////
public static ActionResultResponse determineAndInterpretResult(
final ActionModel model,
final AjaxRequestTarget targetIfAny,
final ObjectAdapter resultAdapter) {
ActionResultResponseType arrt = determineFor(resultAdapter, targetIfAny);
return arrt.interpretResult(model, targetIfAny, resultAdapter);
}
private static ActionResultResponseType determineFor(
final ObjectAdapter resultAdapter,
final AjaxRequestTarget targetIfAny) {
if(resultAdapter == null) {
return ActionResultResponseType.VOID;
}
final ObjectSpecification resultSpec = resultAdapter.getSpecification();
if (resultSpec.isNotCollection()) {
if (resultSpec.getFacet(ValueFacet.class) != null) {
final Object value = resultAdapter.getObject();
if(value instanceof Clob) {
return ActionResultResponseType.VALUE_CLOB;
}
if(value instanceof Blob) {
return ActionResultResponseType.VALUE_BLOB;
}
if(value instanceof java.net.URL) {
return targetIfAny != null? ActionResultResponseType.VALUE_URL_AJAX: ActionResultResponseType.VALUE_URL_NOAJAX;
}
// else
return ActionResultResponseType.VALUE;
} else {
return ActionResultResponseType.OBJECT;
}
} else {
final List<Object> pojoList = asList(resultAdapter);
switch (pojoList.size()) {
case 1:
return ActionResultResponseType.OBJECT;
default:
return ActionResultResponseType.COLLECTION;
}
}
}
@SuppressWarnings("unchecked")
private static List<Object> asList(final ObjectAdapter resultAdapter) {
final Collection<Object> coll = (Collection<Object>) resultAdapter.getObject();
return coll instanceof List
? (List<Object>)coll
: Lists.<Object>newArrayList(coll);
}
}