blob: d96ae96e9c96292503f400b74496ce74d4977f6c [file] [log] [blame]
/*
* Copyright (c) 2010-2020 BSI Business Systems Integration AG.
* 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:
* BSI Business Systems Integration AG - initial API and implementation
*/
package org.eclipse.scout.rt.client.services.lookup;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.eclipse.scout.rt.dataobject.DataObjectHelper;
import org.eclipse.scout.rt.dataobject.lookup.AbstractLookupRestrictionDo;
import org.eclipse.scout.rt.dataobject.lookup.AbstractLookupRowDo;
import org.eclipse.scout.rt.dataobject.lookup.LookupResponse;
import org.eclipse.scout.rt.platform.BEANS;
import org.eclipse.scout.rt.platform.context.RunContext;
import org.eclipse.scout.rt.platform.exception.PlatformException;
import org.eclipse.scout.rt.platform.job.IFuture;
import org.eclipse.scout.rt.platform.job.Jobs;
import org.eclipse.scout.rt.platform.util.CollectionUtility;
import org.eclipse.scout.rt.platform.util.NumberUtility;
import org.eclipse.scout.rt.platform.util.TriState;
import org.eclipse.scout.rt.platform.util.TypeCastUtility;
import org.eclipse.scout.rt.shared.services.lookup.ILookupCall;
import org.eclipse.scout.rt.shared.services.lookup.ILookupRow;
import org.eclipse.scout.rt.shared.services.lookup.ILookupRowFetchedCallback;
import org.eclipse.scout.rt.shared.services.lookup.LookupRow;
/**
* IMPORTANT: If you use subclasses of this lookup call in a smart column, make sure to use an
* {@code org.eclipse.scout.rt.client.ui.basic.table.columns.AbstractRestLookupSmartColumn}, not
* {@code org.eclipse.scout.rt.client.ui.basic.table.columns.AbstractSmartColumn}. Otherwise, batch lookups are
* performed via service tunnel instead of calling a REST service.
*/
public abstract class AbstractRestLookupCall<RESTRICTION extends AbstractLookupRestrictionDo<?, ID>, ID> implements ILookupCall<ID> {
private static final long serialVersionUID = 1L;
protected RESTRICTION m_restrictionDo;
protected AbstractRestLookupCall() {
m_restrictionDo = BEANS.get(resolveRestrictionClass());
}
/**
* Overwrite to resolve to a specific restriction class.
* <p>
* By default, the super hierarchy is looked for the restriction class type in the generic type declaration.
*/
@SuppressWarnings("unchecked")
protected Class<RESTRICTION> resolveRestrictionClass() {
return TypeCastUtility.getGenericsParameterClass(getClass(), AbstractRestLookupCall.class, 0);
}
/**
* @return the live restriction object (not {@code null})
*/
public RESTRICTION getRestriction() {
return m_restrictionDo;
}
@Override
public ID getKey() {
return CollectionUtility.firstElement(m_restrictionDo.getIds());
}
@Override
public void setKey(ID key) {
m_restrictionDo.getIds().clear();
if (key != null) {
m_restrictionDo.getIds().add(key);
}
}
public List<ID> getKeys() {
return m_restrictionDo.getIds();
}
/**
* @deprecated will be removed in 1.3, use {@link #getKeys()} instead
*/
@Deprecated
public List<ID> getIds() {
return getKeys();
}
public void setKeys(Collection<? extends ID> keys) {
m_restrictionDo.withIds(keys);
}
@SafeVarargs
public final void setKeys(@SuppressWarnings("unchecked") ID... keys) {
m_restrictionDo.withIds(keys);
}
@Override
public void setText(String text) {
m_restrictionDo.withText(text);
}
@Override
public void setAll(String s) {
// NOP - unsupported
}
@Override
public String getAll() {
return null;
}
@Override
public void setRec(ID parent) {
// NOP - unsupported
}
@Override
public ID getRec() {
return null;
}
@Override
public void setMaster(Object master) {
// NOP - unsupported
}
@Override
public Object getMaster() {
return null;
}
@Override
public void setActive(TriState activeState) {
m_restrictionDo.withActive(activeState == null ? null : activeState.getBooleanValue());
}
@Override
public TriState getActive() {
return TriState.parse(m_restrictionDo.getActive());
}
@Override
public String getText() {
return m_restrictionDo.getText();
}
@Override
public List<? extends ILookupRow<ID>> getDataByKey() {
if (!m_restrictionDo.ids().exists() || m_restrictionDo.ids().isEmpty()) {
return Collections.emptyList();
}
return getData();
}
@Override
public IFuture<Void> getDataByKeyInBackground(RunContext runContext, ILookupRowFetchedCallback<ID> callback) {
return loadDataInBackground(this::getDataByKey, runContext, callback);
}
@Override
public List<? extends ILookupRow<ID>> getDataByText() {
return getData();
}
@Override
public IFuture<Void> getDataByTextInBackground(RunContext runContext, ILookupRowFetchedCallback<ID> callback) {
return loadDataInBackground(this::getDataByText, runContext, callback);
}
@Override
public List<? extends ILookupRow<ID>> getDataByAll() {
return getData();
}
@Override
public IFuture<Void> getDataByAllInBackground(RunContext runContext, ILookupRowFetchedCallback<ID> callback) {
return loadDataInBackground(this::getDataByAll, runContext, callback);
}
@Override
public List<? extends ILookupRow<ID>> getDataByRec() {
throw new UnsupportedOperationException("not implemented");
}
@Override
public IFuture<Void> getDataByRecInBackground(RunContext runContext, ILookupRowFetchedCallback<ID> callback) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public int getMaxRowCount() {
return NumberUtility.nvl(m_restrictionDo.getMaxRowCount(), 0);
}
@Override
public void setMaxRowCount(int n) {
m_restrictionDo.withMaxRowCount(n);
}
@Override
public String getWildcard() {
return null;
}
@Override
public void setWildcard(String wildcard) {
// NOP - unsupported
}
@Override
public void setMultilineText(boolean b) {
// NOP - unsupported
}
@Override
public boolean isMultilineText() {
return false;
}
protected List<? extends ILookupRow<ID>> getData() {
execPrepareRestriction(m_restrictionDo);
LookupResponse<? extends AbstractLookupRowDo<?, ID>> response = remoteCall().apply(m_restrictionDo);
return transformLookupResponse(response);
}
/**
* Called before remote call to lookup service resource
*/
protected void execPrepareRestriction(RESTRICTION restriction) {
}
/**
* Return function to fetch {@link LookupResponse} from remote
*/
protected abstract Function<RESTRICTION, LookupResponse<? extends AbstractLookupRowDo<?, ID>>> remoteCall();
/**
* Loads data asynchronously, and calls the specified callback once completed.
*/
protected IFuture<Void> loadDataInBackground(final Supplier<List<? extends ILookupRow<ID>>> supplier, final RunContext runContext, final ILookupRowFetchedCallback<ID> callback) {
return Jobs.schedule(() -> loadData(supplier, callback), Jobs.newInput()
.withRunContext(runContext)
.withName("Fetching lookup data [lookupCall={}]", getClass().getName()));
}
/**
* Loads data synchronously, and calls the specified callback once completed.
*/
protected void loadData(final Supplier<List<? extends ILookupRow<ID>>> supplier, final ILookupRowFetchedCallback<ID> callback) {
try {
callback.onSuccess(supplier.get());
}
catch (RuntimeException e) {
callback.onFailure(e);
}
}
/**
* Transforms {@link LookupResponse} with a list of {@link AbstractLookupRowDo} into a list of {@link ILookupRow}.
*/
protected List<? extends ILookupRow<ID>> transformLookupResponse(LookupResponse<? extends AbstractLookupRowDo<?, ID>> response) {
return response.getRows().stream()
.map(this::transformLookupRow)
.collect(Collectors.toList());
}
/**
* Transforms one {@link AbstractLookupRowDo} into a {@link ILookupRow}.
*/
protected ILookupRow<ID> transformLookupRow(AbstractLookupRowDo<?, ID> row) {
return new LookupRow<>(row.getId(), row.getText())
.withActive(row.isActive())
.withEnabled(row.isEnabled())
.withParentKey(row.getParentId());
}
@Override
public AbstractRestLookupCall<RESTRICTION, ID> copy() {
try {
@SuppressWarnings("unchecked")
AbstractRestLookupCall<RESTRICTION, ID> clone = (AbstractRestLookupCall<RESTRICTION, ID>) super.clone();
clone.m_restrictionDo = BEANS.get(DataObjectHelper.class).clone(m_restrictionDo);
return clone;
}
catch (CloneNotSupportedException e) {
throw new PlatformException("could not clone rest lookup call", e);
}
}
@Override
public String toString() {
return getClass().getSimpleName() + "[ m_restrictionDo=" + m_restrictionDo + "]";
}
}