/* * Copyright (C) 2012 Jan Pokorsky * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package cz.cas.lib.proarc.webapp.client.ds; import com.google.gwt.core.shared.GWT; import com.smartgwt.client.data.Criteria; import com.smartgwt.client.data.DSCallback; import com.smartgwt.client.data.DSRequest; import com.smartgwt.client.data.DSResponse; import com.smartgwt.client.data.DataSource; import com.smartgwt.client.data.Record; import com.smartgwt.client.data.RestDataSource; import com.smartgwt.client.data.fields.DataSourceTextField; import com.smartgwt.client.types.DSDataFormat; import com.smartgwt.client.types.PromptStyle; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.BooleanItem; import cz.cas.lib.proarc.webapp.client.ClientMessages; import cz.cas.lib.proarc.webapp.client.ClientUtils; import cz.cas.lib.proarc.webapp.client.Editor; import cz.cas.lib.proarc.webapp.client.action.DeleteAction.Deletable; import cz.cas.lib.proarc.webapp.client.ds.ImportBatchDataSource.BatchRecord; import cz.cas.lib.proarc.webapp.client.ds.MetaModelDataSource.MetaModelRecord; import cz.cas.lib.proarc.webapp.client.widget.StatusView; import cz.cas.lib.proarc.webapp.shared.rest.DigitalObjectResourceApi; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; /** * * @author Jan Pokorsky */ public final class DigitalObjectDataSource extends RestDataSource { public static final String ID = "DigitalObjectDataSource"; public static final String FIELD_PID = DigitalObjectResourceApi.DIGITALOBJECT_PID; public static final String FIELD_MODEL = DigitalObjectResourceApi.DIGITALOBJECT_MODEL; public static final String FIELD_MODS = DigitalObjectResourceApi.NEWOBJECT_XML_PARAM; /** Synthetic attribute holding {@link DigitalObject}. */ private static final String FIELD_INSTANCE = "DIGITALOBJECT_INSTANCE"; private static final Logger LOG = Logger.getLogger(DigitalObjectDataSource.class.getName()); public DigitalObjectDataSource() { setID(ID); setDataFormat(DSDataFormat.JSON); setDataURL(RestConfig.URL_DIGOBJECT); DataSourceTextField pid = new DataSourceTextField(FIELD_PID); pid.setPrimaryKey(true); DataSourceTextField model = new DataSourceTextField(FIELD_MODEL); setFields(pid, model); setOperationBindings(RestConfig.createAddOperation(), RestConfig.createDeleteOperation()); setRequestProperties(RestConfig.createRestRequest(getDataFormat())); } public static DigitalObjectDataSource getInstance() { DigitalObjectDataSource ds = (DigitalObjectDataSource) DataSource.get(ID); return ds != null ? ds : new DigitalObjectDataSource(); } /** * @see cz.cas.lib.proarc.webapp.client.action.DeleteAction */ public static Deletable<Record> createDeletable() { return new Deletable<Record>() { @Override public void delete(Object[] items) { delete(items, null); } @Override public void delete(Object[] items, Record options) { if (items != null && items.length > 0) { String[] pids = ClientUtils.toFieldValues((Record[]) items, DigitalObjectDataSource.FIELD_PID); DigitalObjectDataSource.getInstance().delete(pids, options != null ? options.toMap() : Collections.emptyMap()); } } }; } public static DynamicForm createDeleteOptionsForm() { if (!Editor.getInstance().hasPermission("proarc.permission.admin")) { return null; } ClientMessages i18n = GWT.create(ClientMessages.class); DynamicForm f = new DynamicForm(); BooleanItem opPermanently = new BooleanItem(DigitalObjectResourceApi.DELETE_PURGE_PARAM, i18n.DigitalObjectDeleteAction_OptionPermanently_Title()); opPermanently.setTooltip(i18n.DigitalObjectDeleteAction_OptionPermanently_Hint()); f.setFields(opPermanently); f.setAutoHeight(); return f; } /** * Deletes list of digital objects. * <p>For now it marks whole object hierarchy with state Deleted. * @param pids digital object IDs */ public void delete(String[] pids) { delete(pids, Collections.emptyMap()); } private static String option(Object val, String defval) { return val != null ? val.toString() : defval; } public void delete(String[] pids, Map<?,?> options) { final ClientMessages i18n = GWT.create(ClientMessages.class); HashMap<String, String> deleteParams = new HashMap<String, String>(); deleteParams.put(DigitalObjectResourceApi.DELETE_PURGE_PARAM, option(options.get(DigitalObjectResourceApi.DELETE_PURGE_PARAM), Boolean.FALSE.toString())); deleteParams.put(DigitalObjectResourceApi.DELETE_HIERARCHY_PARAM, option(options.get(DigitalObjectResourceApi.DELETE_HIERARCHY_PARAM), Boolean.TRUE.toString())); DSRequest dsRequest = new DSRequest(); dsRequest.setPromptStyle(PromptStyle.DIALOG); dsRequest.setPrompt(i18n.DeleteAction_Deleting_Msg()); dsRequest.setParams(deleteParams); Record query = new Record(); query.setAttribute(FIELD_PID, pids); DigitalObjectDataSource.getInstance().removeData(query, new DSCallback() { @Override public void execute(DSResponse response, Object rawData, DSRequest request) { if (RestConfig.isStatusOk(response)) { StatusView.getInstance().show(i18n.DeleteAction_Done_Msg()); DigitalObjectDataSource.this.updateCaches(response, request); SearchDataSource.getInstance().updateCaches(response, request); RelationDataSource.getInstance().updateCaches(response, request); } } }, dsRequest); } public static final class DigitalObject { private final String pid; private final String batchId; private final String modelId; private MetaModelRecord model; private Record record; public static DigitalObject create(String pid, String batchId, MetaModelRecord model) { return new DigitalObject(pid, batchId, null, model, null); } public static DigitalObject create(String pid, String batchId, String modelId) { return new DigitalObject(pid, batchId, modelId, null, null); } public static DigitalObject create(Record r) { return create(r, true); } public static DigitalObject createOrNull(Record r) { return create(r, false); } /** * Creates synthetic root object of a batch import. * @param r batch record * @return digital object */ public static DigitalObject create(BatchRecord r) { return create("proarc:root_item", String.valueOf(r.getId()), "none"); } public static DigitalObject[] toArray(Record[] records) { DigitalObject[] dobjs = new DigitalObject[records.length]; for (int i = 0; i < records.length; i++) { dobjs[i] = create(records[i]); } return dobjs; } public static String[] toPidArray(DigitalObject[] objects) { String[] pids = new String[objects.length]; for (int i = 0; i < objects.length; i++) { pids[i] = objects[i].getPid(); } return pids; } /** * Creates digital object instance from record. * @param r record * @param checked {@code false} means ignore missing attributes and return {@code null} * @return instance of digital object */ private static DigitalObject create(Record r, boolean checked) { if (r == null) { throw new NullPointerException(); } DigitalObject dobj = (DigitalObject) r.getAttributeAsObject(FIELD_INSTANCE); if (dobj != null) { return dobj; } String pid = getAttribute(r, FIELD_PID, checked); String modelId = getAttribute(r, FIELD_MODEL, checked); if (pid == null || modelId == null) { return null; } String batchId = r.getAttribute(ModsCustomDataSource.FIELD_BATCHID); MetaModelRecord model = MetaModelDataSource.getModel(r); return new DigitalObject(pid, batchId, modelId, model, r); } public static boolean hasPid(Record r) { return r != null && r.getAttribute(FIELD_PID) != null; } private static String getAttribute(Record r, String fieldName, boolean checked) { String attr = r.getAttribute(fieldName); if (checked && (attr == null || attr.isEmpty())) { throw new IllegalArgumentException(fieldName); } return attr; } private DigitalObject(String pid, String batchId, String modelId, MetaModelRecord model, Record record) { if (pid == null || pid.isEmpty()) { throw new IllegalArgumentException("PID"); } this.pid = pid; this.batchId = batchId; this.modelId = model == null ? modelId : model.getId(); this.model = model; if (this.modelId == null || this.modelId.isEmpty()) { throw new IllegalArgumentException("No model for: " + pid); } this.record = record; if (record != null) { record.setAttribute(FIELD_INSTANCE, this); } } public String getPid() { return pid; } public String getBatchId() { return batchId; } public Integer getBatchIdAsInt() { return batchId == null ? null : Integer.valueOf(batchId); } public String getModelId() { return modelId; } public MetaModelRecord getModel() { return model; } public Record getRecord() { if (record == null) { record = toRecord(); } return record; } /** * Gets always a new instance of Record. */ public Record toRecord() { Record r = new Record(); r.setAttribute(FIELD_PID, pid); r.setAttribute(FIELD_MODEL, modelId); if (batchId != null) { r.setAttribute(ModsCustomDataSource.FIELD_BATCHID, batchId); } if (model != null) { r.setAttribute(MetaModelDataSource.FIELD_MODELOBJECT, model); } r.setAttribute(FIELD_INSTANCE, this); return r; } public Criteria toCriteria() { Criteria criteria = new Criteria(FIELD_PID, pid); if (batchId != null) { criteria.addCriteria(ModsCustomDataSource.FIELD_BATCHID, batchId); } return criteria; } @Override public String toString() { return "DigitalObject{" + "pid=" + pid + ", batchId=" + batchId + ", modelId=" + modelId + ", model=" + model + '}'; } } }