package org.orienteer.core.module;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import javax.inject.Singleton;
import org.apache.wicket.Component;
import org.apache.wicket.resource.loader.IStringResourceLoader;
import org.apache.wicket.util.string.Strings;
import org.orienteer.core.CustomAttribute;
import org.orienteer.core.OrienteerWebApplication;
import org.orienteer.core.OrienteerWebSession;
import org.orienteer.core.util.OSchemaHelper;
import ru.ydn.wicket.wicketorientdb.OrientDbWebSession;
import ru.ydn.wicket.wicketorientdb.utils.DBClosure;
import com.google.common.primitives.Booleans;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.hook.ODocumentHookAbstract;
import com.orientechnologies.orient.core.hook.ORecordHook;
import com.orientechnologies.orient.core.hook.ORecordHook.DISTRIBUTED_EXECUTION_MODE;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.metadata.schema.OSchema;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.metadata.schema.OClass.INDEX_TYPE;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
/**
* {@link IOrienteerModule} to simplify localization of an application
*/
@Singleton
public class OrienteerLocalizationModule extends AbstractOrienteerModule
{
public static final String NAME = "localization";
public static final String OCLASS_LOCALIZATION="OLocalization";
public static final String OCLASS_USER="OUser";
public static final String OPROPERTY_KEY="key";
public static final String OPROPERTY_LANG="lang";
public static final String OPROPERTY_STYLE="style";
public static final String OPROPERTY_VARIATION="variation";
public static final String OPROPERTY_ACTIVE="active";
public static final String OPROPERTY_VALUE="value";
public static final String OPROPERTY_LOCALE="locale";
public static final String ODOCUMENT_LOCALIZATION_VISUALIZER="localization";
/**
* {@link ORecordHook} to invalidate localization cache if something changed
*/
public static class LocalizationInvalidationHook extends ODocumentHookAbstract {
public LocalizationInvalidationHook(ODatabaseDocument database) {
super(database);
setIncludeClasses(OCLASS_LOCALIZATION);
}
private void invalidateCache()
{
OrienteerWebApplication app = OrienteerWebApplication.lookupApplication();
if(app!=null)
{
app.getResourceSettings().getLocalizer().clearCache();
}
}
@Override
public void onRecordAfterCreate(ODocument iDocument) {
invalidateCache();
}
@Override
public void onRecordAfterUpdate(ODocument iDocument) {
invalidateCache();
}
@Override
public void onRecordAfterDelete(ODocument iDocument) {
invalidateCache();
}
@Override
public DISTRIBUTED_EXECUTION_MODE getDistributedExecutionMode() {
return DISTRIBUTED_EXECUTION_MODE.BOTH;
}
};
private static class OrienteerStringResourceLoader implements IStringResourceLoader
{
@Override
public String loadStringResource(Class<?> clazz, String key,
Locale locale, String style, String variation) {
return loadStringResource(key, locale, style, variation);
}
@Override
public String loadStringResource(Component component, String key,
Locale locale, String style, String variation) {
return loadStringResource(key, locale, style, variation);
}
public String loadStringResource(final String key, Locale locale, final String style, final String variation)
{
if(Strings.isEmpty(key)) {
System.out.println("Empty!");
}
final String language = locale!=null?locale.getLanguage():null;
return new DBClosure<String>() {
@Override
protected String execute(ODatabaseDocument db) {
OSQLSynchQuery<ODocument> query = new OSQLSynchQuery<ODocument>("select from "+OCLASS_LOCALIZATION+" where "+OPROPERTY_KEY+" = ?");
List<ODocument> result = db.command(query).execute(key);
if(result==null || result.isEmpty())
{
registerStringResourceRequest(key, language, style, variation);
return null;
}
ODocument bestCandidate = null;
int bestCandidateScore = -1;
boolean fullMatchPresent=false;
for (ODocument candidate : result)
{
int score = 0;
if(Strings.isEqual(language, (String)candidate.field(OPROPERTY_LANG)))score|=1<<2;
if(Strings.isEqual(style, (String)candidate.field(OPROPERTY_STYLE)))score|=1<<1;
if(Strings.isEqual(variation, (String)candidate.field(OPROPERTY_VARIATION)))score|=1;
if(score==7) fullMatchPresent=true;
Boolean active = candidate.field(OPROPERTY_ACTIVE);
if(active==null || !active) score=-1;
if(score>bestCandidateScore)
{
bestCandidate = candidate;
bestCandidateScore=score;
}
}
if(!fullMatchPresent)
{
registerStringResourceRequest(key, language, style, variation);
}
return bestCandidate!=null?(String)bestCandidate.field(OPROPERTY_VALUE):null;
}
}.execute();
}
private void registerStringResourceRequest(String key, String language, String style, String variation)
{
ODocument doc = new ODocument(OCLASS_LOCALIZATION);
doc.field(OPROPERTY_KEY, key);
doc.field(OPROPERTY_LANG, language);
doc.field(OPROPERTY_STYLE, style);
doc.field(OPROPERTY_VARIATION, variation);
doc.field(OPROPERTY_ACTIVE, false);
doc.save();
}
}
public OrienteerLocalizationModule()
{
super(NAME, 1);
}
@Override
public ODocument onInstall(OrienteerWebApplication app, ODatabaseDocument db) {
OSchemaHelper helper = OSchemaHelper.bind(db);
helper.oClass(OCLASS_LOCALIZATION)
.oProperty(OPROPERTY_KEY, OType.STRING)
.markAsDocumentName()
.oIndex("key_index", INDEX_TYPE.NOTUNIQUE)
.oProperty(OPROPERTY_LANG, OType.STRING)
.oProperty(OPROPERTY_STYLE, OType.STRING)
.oProperty(OPROPERTY_VARIATION, OType.STRING)
.oProperty(OPROPERTY_ACTIVE, OType.BOOLEAN)
.oProperty(OPROPERTY_VALUE, OType.STRING).assignVisualization("textarea")
.orderProperties(OPROPERTY_KEY, OPROPERTY_ACTIVE, OPROPERTY_LANG, OPROPERTY_STYLE, OPROPERTY_VARIATION, OPROPERTY_VALUE)
.switchDisplayable(true, OPROPERTY_KEY, OPROPERTY_ACTIVE, OPROPERTY_LANG, OPROPERTY_STYLE, OPROPERTY_VARIATION, OPROPERTY_VALUE);
helper.oClass(OCLASS_USER).oProperty(OPROPERTY_LOCALE, OType.STRING);
return null;
}
@Override
public void onUninstall(OrienteerWebApplication app, ODatabaseDocument db) {
OSchema schema = app.getDatabase().getMetadata().getSchema();
if(schema.existsClass(OCLASS_LOCALIZATION)) schema.dropClass(OCLASS_LOCALIZATION);
}
@Override
public void onInitialize(OrienteerWebApplication app, ODatabaseDocument db) {
app.getResourceSettings().getStringResourceLoaders().add(new OrienteerStringResourceLoader());
app.getOrientDbSettings().getORecordHooks().add(LocalizationInvalidationHook.class);
}
@Override
public void onDestroy(OrienteerWebApplication app, ODatabaseDocument db) {
Iterator<IStringResourceLoader> it = app.getResourceSettings().getStringResourceLoaders().iterator();
while (it.hasNext()){
if(it.next() instanceof OrienteerStringResourceLoader) it.remove();
}
app.getOrientDbSettings().getORecordHooks().remove(LocalizationInvalidationHook.class);
}
}