/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.index.service.catalog.adapter;
import static com.entwinemedia.fn.data.json.Jsons.arr;
import static com.entwinemedia.fn.data.json.Jsons.f;
import static com.entwinemedia.fn.data.json.Jsons.obj;
import static com.entwinemedia.fn.data.json.Jsons.v;
import org.opencastproject.mediapackage.MediaPackageElementFlavor;
import org.opencastproject.metadata.dublincore.EventCatalogUIAdapter;
import org.opencastproject.metadata.dublincore.MetadataCollection;
import org.opencastproject.metadata.dublincore.MetadataField;
import org.opencastproject.metadata.dublincore.MetadataParsingException;
import org.opencastproject.metadata.dublincore.SeriesCatalogUIAdapter;
import org.opencastproject.util.data.Tuple;
import com.entwinemedia.fn.Fn;
import com.entwinemedia.fn.Fn2;
import com.entwinemedia.fn.Stream;
import com.entwinemedia.fn.data.Opt;
import com.entwinemedia.fn.data.json.Field;
import com.entwinemedia.fn.data.json.JValue;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
public final class MetadataList implements Iterable<Entry<String, Tuple<String, MetadataCollection>>> {
public enum Locked {
NONE("NONE"), WORKFLOW_RUNNING("EVENTS.EVENTS.DETAILS.METADATA.LOCKED.RUNNING");
private String languageConstant;
Locked(String languageConstant) {
this.languageConstant = languageConstant;
}
public String getValue() {
return languageConstant;
}
}
private static final String KEY_METADATA_TITLE = "title";
private static final String KEY_METADATA_FLAVOR = "flavor";
private static final String KEY_METADATA_FIELDS = "fields";
private static final String KEY_METADATA_LOCKED = "locked";
private Map<String, Tuple<String, MetadataCollection>> metadataList = new HashMap<>();
private Locked locked = Locked.NONE;
public MetadataList() {
}
public MetadataList(MetadataCollection metadata, String json) throws MetadataParsingException {
this();
fromJSON(metadata, json);
}
public JValue toJSON() {
List<JValue> catalogs = new ArrayList<>();
for (Entry<String, Tuple<String, MetadataCollection>> metadata : metadataList.entrySet()) {
List<Field> fields = new ArrayList<>();
MetadataCollection metadataCollection = metadata.getValue().getB();
if (!Locked.NONE.equals(locked)) {
fields.add(f(KEY_METADATA_LOCKED, v(locked.getValue())));
makeMetadataCollectionReadOnly(metadataCollection);
}
fields.add(f(KEY_METADATA_FLAVOR, v(metadata.getKey())));
fields.add(f(KEY_METADATA_TITLE, v(metadata.getValue().getA())));
fields.add(f(KEY_METADATA_FIELDS, metadataCollection.toJSON()));
catalogs.add(obj(fields));
}
return arr(catalogs);
}
private void makeMetadataCollectionReadOnly(MetadataCollection metadataCollection) {
for (MetadataField<?> field : metadataCollection.getFields())
field.setReadOnly(true);
}
public void fromJSON(String json) throws MetadataParsingException {
if (StringUtils.isBlank(json))
throw new IllegalArgumentException("The JSON string must not be empty or null!");
JSONParser parser = new JSONParser();
JSONArray metadataJSON;
try {
metadataJSON = (JSONArray) parser.parse(json);
} catch (ParseException e) {
throw new MetadataParsingException("Not able to parse the given string as JSON metadata list.", e.getCause());
}
ListIterator<JSONObject> listIterator = metadataJSON.listIterator();
while (listIterator.hasNext()) {
JSONObject item = listIterator.next();
MediaPackageElementFlavor flavor = MediaPackageElementFlavor.parseFlavor((String) item.get(KEY_METADATA_FLAVOR));
String title = (String) item.get(KEY_METADATA_TITLE);
if (flavor == null || title == null)
continue;
JSONArray value = (JSONArray) item.get(KEY_METADATA_FIELDS);
if (value == null)
continue;
Tuple<String, MetadataCollection> metadata = metadataList.get(flavor.toString());
if (metadata == null)
continue;
metadata.getB().fromJSON(value.toJSONString());
metadataList.put(flavor.toString(), metadata);
}
}
private void fromJSON(MetadataCollection metadata, String json) throws MetadataParsingException {
if (StringUtils.isBlank(json))
throw new IllegalArgumentException("The JSON string must not be empty or null!");
JSONParser parser = new JSONParser();
JSONArray metadataJSON;
try {
metadataJSON = (JSONArray) parser.parse(json);
} catch (ParseException e) {
throw new MetadataParsingException("Not able to parse the given string as JSON metadata list.", e.getCause());
}
ListIterator<JSONObject> listIterator = metadataJSON.listIterator();
while (listIterator.hasNext()) {
JSONObject item = listIterator.next();
String flavor = (String) item.get(KEY_METADATA_FLAVOR);
String title = (String) item.get(KEY_METADATA_TITLE);
if (flavor == null || title == null)
continue;
JSONArray value = (JSONArray) item.get(KEY_METADATA_FIELDS);
if (value == null)
continue;
metadata.fromJSON(value.toJSONString());
metadataList.put(flavor, Tuple.tuple(title, metadata));
}
}
public Opt<MetadataCollection> getMetadataByAdapter(SeriesCatalogUIAdapter catalogUIAdapter) {
return Stream.$(metadataList.keySet()).filter(adapterFilter._2(catalogUIAdapter.getFlavor().toString()))
.map(toMetadata).head();
}
public Opt<MetadataCollection> getMetadataByAdapter(EventCatalogUIAdapter catalogUIAdapter) {
return Stream.$(metadataList.keySet()).filter(adapterFilter._2(catalogUIAdapter.getFlavor().toString()))
.map(toMetadata).head();
}
public Opt<MetadataCollection> getMetadataByFlavor(String flavor) {
return Stream.$(metadataList.keySet()).filter(adapterFilter._2(flavor)).map(toMetadata).head();
}
private static final Fn2<String, String, Boolean> adapterFilter = new Fn2<String, String, Boolean>() {
@Override
public Boolean apply(String key, String flavor) {
return key.equals(flavor);
}
};
private final Fn<String, MetadataCollection> toMetadata = new Fn<String, MetadataCollection>() {
@Override
public MetadataCollection apply(String key) {
return metadataList.get(key).getB();
}
};
public void add(EventCatalogUIAdapter adapter, MetadataCollection metadata) {
metadataList.put(adapter.getFlavor().toString(), Tuple.tuple(adapter.getUITitle(), metadata));
}
public void add(SeriesCatalogUIAdapter adapter, MetadataCollection metadata) {
metadataList.put(adapter.getFlavor().toString(), Tuple.tuple(adapter.getUITitle(), metadata));
}
public void add(String flavor, String title, MetadataCollection metadata) {
metadataList.put(flavor, Tuple.tuple(title, metadata));
}
@Override
public Iterator<Entry<String, Tuple<String, MetadataCollection>>> iterator() {
return metadataList.entrySet().iterator();
}
public void setLocked(Locked locked) {
this.locked = locked;
}
}