/**
*
* Copyright
* 2009-2015 Jayway Products AB
* 2016-2017 Föreningen Sambruk
*
* Licensed under AGPL, Version 3.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.gnu.org/licenses/agpl.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 se.streamsource.streamflow.web.infrastructure.index;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.core.SolrCore;
import org.apache.solr.schema.SchemaField;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.openrdf.model.BNode;
import org.openrdf.model.Graph;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.model.impl.GraphImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.qi4j.api.injection.scope.Service;
import org.qi4j.api.injection.scope.Uses;
import org.qi4j.api.service.Activatable;
import org.qi4j.library.rdf.entity.EntityStateSerializer;
import org.qi4j.spi.entity.EntityState;
import org.qi4j.spi.entity.EntityStatus;
import org.qi4j.spi.entitystore.StateChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.streamsource.streamflow.util.Translator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* JAVADOC Add JavaDoc
*/
public class SolrEntityIndexerMixin
implements StateChangeListener, Activatable
{
@Service
private EmbeddedSolrService solr;
@Uses
private EntityStateSerializer stateSerializer;
private ValueFactory valueFactory = new ValueFactoryImpl();
private SolrServer server;
private Map<String, SchemaField> indexedFields;
Logger logger = LoggerFactory.getLogger( getClass() );
public void activate() throws Exception
{
server = solr.getSolrServer( "sf-core" );
SolrCore solrCore = solr.getSolrCore( "sf-core" );
if( solrCore == null)
return;
try
{
indexedFields = solrCore.getLatestSchema().getFields();
} finally
{
solrCore.close();
}
}
public void passivate() throws Exception
{
server = null;
indexedFields = null;
}
public void notifyChanges( Iterable<EntityState> entityStates )
{
try
{
// Figure out what to update
List<String> deleted = null;
List<SolrInputDocument> added = new ArrayList<SolrInputDocument>();
for (EntityState entityState : entityStates)
{
if (entityState.entityDescriptor().entityType().queryable())
{
if (entityState.status().equals( EntityStatus.REMOVED ))
{
if (deleted == null)
deleted = new ArrayList<String>();
deleted.add( entityState.identity().identity() );
} else if (entityState.status().equals( EntityStatus.UPDATED ))
{
added.add( indexEntityState( entityState, server ) );
} else if (entityState.status().equals( EntityStatus.NEW ))
{
added.add( indexEntityState( entityState, server ) );
}
}
}
// Send changes to Solr
if (deleted != null)
server.deleteById( deleted );
if (!added.isEmpty())
server.add( added );
}
catch (Throwable e)
{
logger.error( "Could not update Solr", e );
//TODO What shall we do with the exception?
}
}
private SolrInputDocument indexEntityState( final EntityState entityState,
final SolrServer server )
throws IOException, SolrServerException, JSONException
{
Graph graph = new GraphImpl();
stateSerializer.serialize( entityState, false, graph );
SolrInputDocument input = new SolrInputDocument();
input.addField( "id", entityState.identity().identity() );
input.addField( "type", entityState.entityDescriptor().entityType().type().name() );
input.addField( "lastModified", new Date( entityState.lastModified() ) );
for (Statement statement : graph)
{
SchemaField field = indexedFields.get( statement.getPredicate().getLocalName() );
if (field != null)
{
if (statement.getObject() instanceof Literal)
{
String value = statement.getObject().stringValue();
if (field.getType().getTypeName().equals( "json" ))
{
if (value.charAt( 0 ) == '[')
{
JSONArray array = new JSONArray( value );
indexJson( input, array, field.getName() );
} else if (value.charAt( 0 ) == '{')
{
JSONObject object = new JSONObject( value );
indexJson( input, object, field.getName());
}
} else
{
input.addField( field.getName(), value );
}
} else if (statement.getObject() instanceof URI && !"type".equals( field.getName() ))
{
String value = statement.getObject().stringValue();
value = value.substring( value.lastIndexOf( ':' ) + 1, value.length() );
String name = field.getName();
input.addField( name, value );
} else if (statement.getObject() instanceof BNode)
{
Iterator<Statement> seq = graph.match( (Resource) statement.getObject(), new URIImpl( "http://www.w3.org/1999/02/22-rdf-syntax-ns#li" ), null, (Resource) null );
while (seq.hasNext())
{
Statement seqStatement = seq.next();
String value = seqStatement.getObject().stringValue();
value = value.substring( value.lastIndexOf( ':' ) + 1, value.length() );
input.addField( field.getName(), value );
}
}
}
}
return input;
}
private void indexJson(SolrInputDocument input, Object object, String fieldName) throws JSONException
{
if (object instanceof JSONArray)
{
JSONArray array = (JSONArray) object;
for (int i = 0; i < array.length(); i++)
indexJson( input, array.get( i ), fieldName);
} else if (object instanceof JSONObject)
{
JSONObject jsonObject = (JSONObject) object;
Iterator keys = jsonObject.keys();
while (keys.hasNext())
{
Object name = keys.next();
Object value = jsonObject.get( name.toString() );
if (value instanceof JSONObject || value instanceof JSONArray)
{
indexJson( input, value, fieldName);
} else
{
SchemaField field = indexedFields.get( name.toString() );
if (field != null)
{
// if note is html formatted - remove html tags
if( "note".equals( name.toString() ) )
{
String contentType = "";
try
{
contentType = (String)jsonObject.get( "contentType" );
}catch (JSONException je )
{
//do nothing
}
if( Translator.HTML.equals( contentType ) )
{
input.addField( name.toString(), Translator.htmlToText( (String)jsonObject.get( name.toString() ) ) );
} else
{
input.addField( name.toString(), jsonObject.get( name.toString() ) );
}
} else
{
input.addField( name.toString(), jsonObject.get( name.toString() ) );
}
}
}
}
} else
{
if (object != null)
input.addField(fieldName, object.toString());
}
}
}