/*******************************************************************************
* Copyright 2012 The Infinit.e Open Source Project
*
* Licensed 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 com.ikanow.infinit.e.data_model.api.config;
import java.lang.reflect.Type;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import org.bson.types.ObjectId;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.ikanow.infinit.e.data_model.api.BaseApiPojo;
import com.ikanow.infinit.e.data_model.api.BasePojoApiMap;
import com.ikanow.infinit.e.data_model.store.config.source.SourceFederatedQueryConfigPojo;
import com.ikanow.infinit.e.data_model.store.config.source.SourcePipelinePojo;
import com.ikanow.infinit.e.data_model.store.config.source.SourcePojo;
import com.ikanow.infinit.e.data_model.store.config.source.SourceRssConfigPojo;
import com.ikanow.infinit.e.data_model.store.config.source.StructuredAnalysisConfigPojo;
import com.ikanow.infinit.e.data_model.store.config.source.UnstructuredAnalysisConfigPojo;
// When retrieving a source object, need to restrict visibility of communities to
// those allowed to know
public class SourcePojoApiMap implements BasePojoApiMap<SourcePojo> {
// Construction:
public SourcePojoApiMap(ObjectId userId, Set<ObjectId> allowedCommunityIds, Set<ObjectId> ownedOrModeratedCommunities) {
_userId = userId;
_allowedCommunityIds = allowedCommunityIds;
_ownedOrModeratedCommunities = ownedOrModeratedCommunities;
}
// NOTE: auto set key can only be done for testing, since it doesn't guarantee uniqueness...
public SourcePojoApiMap(Set<ObjectId> allowedCommunityIds) {
_allowedCommunityIds = allowedCommunityIds;
}
private Set<ObjectId> _allowedCommunityIds = null;
private ObjectId _userId = null; // (stays null for admin)
private Set<ObjectId> _ownedOrModeratedCommunities = null;
public GsonBuilder extendBuilder(GsonBuilder gb) {
return gb.registerTypeAdapter(SourcePojo.class, new SourcePojoSerializer(_userId, _allowedCommunityIds, _ownedOrModeratedCommunities)).
registerTypeAdapter(SourcePojo.class, new SourcePojoDeserializer(_allowedCommunityIds));
}
// Custom serialization:
protected static class SourcePojoSerializer implements JsonSerializer<SourcePojo>
{
private Set<ObjectId> _allowedCommunityIds = null;
private ObjectId _userId;
private Set<ObjectId> _ownedOrModeratedCommunities = null;
SourcePojoSerializer(ObjectId userId, Set<ObjectId> allowedCommunityIds, Set<ObjectId> ownedOrModeratedCommunities) {
_userId = userId;
_allowedCommunityIds = allowedCommunityIds;
_ownedOrModeratedCommunities = ownedOrModeratedCommunities;
}
@Override
public JsonElement serialize(SourcePojo source, Type typeOfT, JsonSerializationContext context)
{
boolean bIsPublic = false;
if (source.isPublic() || (null == _userId) || _userId.equals(source.getOwnerId())) {
// (null if admin)
bIsPublic = true;
}
// (else check below vs community list)
Set<ObjectId> tmp = source.getCommunityIds();
if (null != tmp) {
source.setCommunityIds(null);
for (ObjectId communityID: tmp) {
if (_allowedCommunityIds.contains(communityID)) {
source.addToCommunityIds(communityID);
if (!bIsPublic) {
if (_ownedOrModeratedCommunities.contains(communityID)) {
bIsPublic = true;
}
}
}
}
}
// (saved fields to rewrite later if not public, do up here for visibility)
String url = source.getUrl();
SourceRssConfigPojo rss = source.getRssConfig();
List<SourcePipelinePojo> pxPipe = source.getProcessingPipeline();
StructuredAnalysisConfigPojo sah = source.getStructuredAnalysisConfig();
UnstructuredAnalysisConfigPojo uah = source.getUnstructuredAnalysisConfig();
if (!bIsPublic) { // Cleanse URLs, remove processing pipeline information
source.setPartiallyPublished(true); //TESTED
// Copy URL info from px pipeline into the main source
if ((null != source.getProcessingPipeline()) && !source.getProcessingPipeline().isEmpty()) {
SourcePipelinePojo firstEl = source.getProcessingPipeline().iterator().next();
if (null != firstEl.web) {
source.setRssConfig(firstEl.web);
}
else if (null != firstEl.feed) {
source.setRssConfig(firstEl.feed);
}
else if (null != firstEl.database) {
source.setUrl(firstEl.database.getUrl());
}
else if (null != firstEl.file) {
source.setUrl(firstEl.file.getUrl());
}
source.setProcessingPipeline(new ArrayList<SourcePipelinePojo>()); // (delete px pipeline)
}//(end if non-empty px pipeline)
//TESTED
int nIndex = -1;
if ((null != url) && ((nIndex = url.indexOf('?')) >= 0)) {
source.setUrl(url.substring(0, 1 + nIndex));
}
if (null != rss) {
rss.setHttpFields(null); // (remove cookie information)
}
if ((null != rss) && (null != rss.getExtraUrls())) {
SourceRssConfigPojo newRss = new SourceRssConfigPojo();
ArrayList<SourceRssConfigPojo.ExtraUrlPojo> newList = new ArrayList<SourceRssConfigPojo.ExtraUrlPojo>(rss.getExtraUrls().size());
for (SourceRssConfigPojo.ExtraUrlPojo urlObj: rss.getExtraUrls()) {
SourceRssConfigPojo.ExtraUrlPojo newUrlObj = new SourceRssConfigPojo.ExtraUrlPojo();
if ((null != urlObj.url) && ((nIndex = urlObj.url.indexOf('?')) >= 0)) {
newUrlObj.url = urlObj.url.substring(0, 1 + nIndex);
}
else {
newUrlObj.url = urlObj.url;
}
newUrlObj.title = urlObj.title;
newUrlObj.description = urlObj.description;
newUrlObj.publishedDate = urlObj.publishedDate;
newUrlObj.fullText = urlObj.fullText;
newList.add(newUrlObj);
}
newRss.setExtraUrls(newList);
source.setRssConfig(newRss);
}
else if (null != rss) {
source.setRssConfig(null);
}
if (null != source.getStructuredAnalysisConfig()) {
source.setStructuredAnalysisConfig(new StructuredAnalysisConfigPojo());
}//TESTED
if (null != source.getUnstructuredAnalysisConfig()) {
source.setUnstructuredAnalysisConfig(new UnstructuredAnalysisConfigPojo());
}//TESTED
}
//TESTED (extraUrls with and without ?s, RSS/no extraURLs, URL)
if (null == source.getCommunityIds()) { // Somehow a security error has occurred
//Exception out and hope for the best!
throw new RuntimeException("Insufficient access permissions on this object");
}
JsonElement json = BaseApiPojo.getDefaultBuilder().create().toJsonTree(source);
if (!bIsPublic) { // Remove a load of potentially sensitive information
JsonObject jsonObj = json.getAsJsonObject();
//(url cleansed above)
jsonObj.remove(SourcePojo.database_);
jsonObj.remove(SourcePojo.file_);
//(rss cleansed above)
jsonObj.remove(SourcePojo.authentication_);
// Ensure the POJO isn't modified by the mapping (part 1)
source.setUrl(url);
source.setRssConfig(rss);
source.setProcessingPipeline(pxPipe);
source.setUnstructuredAnalysisConfig(uah);
source.setStructuredAnalysisConfig(sah);
source.setPartiallyPublished(null);
}
// Ensure the POJO isn't modified by the mapping (part 2)
if (null != tmp) {
source.setCommunityIds(tmp);
}
return json;
}
}//TESTED (private: yes, public sources: yes, owned sources: yes, non-owner/own community: yes)
protected static class SourcePojoDeserializer implements JsonDeserializer<SourcePojo>
{
private Set<ObjectId> _allowedCommunityIds = null;
SourcePojoDeserializer(Set<ObjectId> allowedCommunityIds) {
_allowedCommunityIds = allowedCommunityIds;
}
@Override
public SourcePojo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
SourcePojo source = new SourceFederatedQueryConfigPojo().extendBuilder(BaseApiPojo.getDefaultBuilder()).create().fromJson(json, SourcePojo.class);
if (null != _allowedCommunityIds) {
source.setCommunityIds(null);
for (ObjectId communityId: _allowedCommunityIds) {
source.addToCommunityIds(communityId);
}
}
return source;
}
}
}