Preferences -- PreferenceProvider the Implment


package org.jboss.seam.wiki.core.preferences;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.*;
import org.jboss.seam.log.Log;
import org.jboss.seam.wiki.core.model.User;
import org.jboss.seam.wiki.core.plugin.WikiPluginMacro;
import org.jboss.seam.wiki.preferences.PreferenceProvider;
import org.jboss.seam.wiki.preferences.PreferenceValue;
import org.jboss.seam.wiki.preferences.PreferenceVisibility;
import org.jboss.seam.wiki.preferences.metamodel.PreferenceEntity;
import org.jboss.seam.wiki.preferences.metamodel.PreferenceRegistry;

import javax.persistence.EntityManager;
import java.io.Serializable;
import java.util.*;

/**
* Implementation for the wiki, loads and stores <tt>WikiPreferenceValue</tt> objects.
* <p>
* This implementation tries to be as smart as possible and supports multi-level preference value overrides.
* If you load values, they are automatically resolved for system, user, and instance levels. If a value is
* present at system level but you want values for users, this implementation creates and returns those
* missing values. It will also persist them if you call <tt>store()</tt> and <tt>flush()</tt>.
* </p>
* <p>
* System and user-level values are loaded and stored in the database with the <tt>entityManager</tt>
* persistence context. be careful to only flush it if you want to after you retrieved and modified
* values with this provider.
* </p>
* <p>
* Instance-level values are not stored in the database, they are marshalled by converting <tt>WikiMacro</tt>
* (the instance this provider understands) parameters.
* </p>
*
* @author Christian Bauer
*/
@Name("preferenceProvider")
@AutoCreate
@Scope(ScopeType.CONVERSATION)
public class WikiPreferenceProvider implements PreferenceProvider<User, WikiPluginMacro>, Serializable {

@Logger Log log;

@In
EntityManager entityManager;

@In
PreferenceRegistry preferenceRegistry;

// Queue in current conversation until flush()
List<PreferenceValue> newValueHolders = new ArrayList<PreferenceValue>();

public Set<PreferenceValue> loadValues(String preferenceEntityName,
User user, WikiPluginMacro instance,
List<PreferenceVisibility> visibilities) {

log.debug("assembling preference values for '"
+ preferenceEntityName
+ "' and user '" + user
+ "' and wiki macro ' " + instance + "'");

PreferenceEntity entity = preferenceRegistry.getPreferenceEntitiesByName().get(preferenceEntityName);
SortedSet<PreferenceValue> valueHolders = new TreeSet<PreferenceValue>();

Set<PreferenceValue> systemValueHolders = null;
if (visibilities.contains(PreferenceVisibility.SYSTEM)) {
log.trace("retrieving SYSTEM preference values from database");

systemValueHolders = loadSystemValues(preferenceEntityName);

// Check if all SYSTEM-level properties were present in the database
for (PreferenceEntity.Property systemVisibleProperty : entity.getPropertiesSystemVisible()) {
WikiPreferenceValue newValueHolder = new WikiPreferenceValue(systemVisibleProperty);
// If not, queue a new value holder (with a null "value") for that property and return it
if (!systemValueHolders.contains(newValueHolder)) {
systemValueHolders.add(newValueHolder);
newValueHolders.add(newValueHolder);
}
}
valueHolders.addAll(systemValueHolders);
}

Set<PreferenceValue> userValueHolders;
if (visibilities.contains(PreferenceVisibility.USER)) {
if (user == null)
throw new IllegalArgumentException("can't load preferences for null user");
log.trace("retrieving USER preference values from database");

userValueHolders = loadUserValues(preferenceEntityName, user);

// We need them when we iterate through missing properties next
if (systemValueHolders == null) systemValueHolders = loadSystemValues(preferenceEntityName);

// Check if all USER-level properties were present in the database
for (PreferenceEntity.Property userVisibleProperty : entity.getPropertiesUserVisible()) {
WikiPreferenceValue newValueHolder = new WikiPreferenceValue(userVisibleProperty);

// If not, queue a new value for that property and return it
if (!userValueHolders.contains(newValueHolder)) {
log.trace("creating new preference value for user, missing in database " + userVisibleProperty);
userValueHolders.add(newValueHolder);
newValueHolders.add(newValueHolder);

newValueHolder.setUser(user);

// We need a "value" for that property, let's check if we have a SYSTEM-level property we can take it from
if (userVisibleProperty.getVisibility().contains(PreferenceVisibility.SYSTEM) &&
systemValueHolders != null && systemValueHolders.contains(newValueHolder)) {
for (PreferenceValue systemValue : systemValueHolders) {
if (systemValue.equals(newValueHolder)) {
log.trace("taking the initial value from the SYSTEM-level setting");
newValueHolder.setValue(systemValue.getValue());
newValueHolder.setDirty(false); // New value isn't dirty, by definition
}
}
}
// If we don't have a value, well, then it's null (this is a property with USER and no SYSTEM visibility)
}
}

// Override SYSTEM values
valueHolders.removeAll(userValueHolders);
valueHolders.addAll(userValueHolders);
}

if (visibilities.contains(PreferenceVisibility.INSTANCE)) {
if (instance == null)
throw new IllegalArgumentException("can't load preferences for null WikiMacro instance");
log.trace("extracting INSTANCE preference values from " + instance);
Set<PreferenceValue> instanceValues = loadInstanceValues(preferenceEntityName, instance);
// Override SYSTEM and USER values
valueHolders.removeAll(instanceValues);
valueHolders.addAll(instanceValues);
}

return valueHolders;
}

public void storeValues(Set<PreferenceValue> valueHolders, User user, WikiPluginMacro instance) {
// TODO: We don't care about the arguments, maybe instance later on when we marshall stuff into WikiMacro params

// The new ones need to be checked if they are dirty and manually persisted
for (PreferenceValue newPreferenceValue : newValueHolders) {
if (newPreferenceValue.isDirty()) {
log.debug("storing new preference value " + newPreferenceValue);
entityManager.persist(newPreferenceValue);
}
}

// The old ones are automatically checked for dirty state by Hibernate

}

public void deleteUserPreferenceValues(User user) {
log.debug("deleting preferences of user: " + user);
List<WikiPreferenceValue> values =
entityManager.createQuery(
"select wp from WikiPreferenceValue wp" +
" where wp.user = :user"
).setParameter("user", user)
.getResultList();
for (WikiPreferenceValue value : values) {
entityManager.remove(value);
}
}

public void flush() {
log.debug("flushing preference provider");
entityManager.flush();

// Reset queue
newValueHolders = new ArrayList<PreferenceValue>();
}


/* ######################################### IMPLEMENTATION DETAILS ######################################### */

private Set<PreferenceValue> loadSystemValues(String entityName) {
List<WikiPreferenceValue> values =
entityManager.createQuery(
"select wp from WikiPreferenceValue wp" +
" where wp.entityName = :name and wp.user is null"
).setParameter("name", entityName)
.setHint("org.hibernate.cacheable", true)
.getResultList();
setPropertyReferences(values, entityName, PreferenceVisibility.SYSTEM);
return new HashSet(values);
}

private Set<PreferenceValue> loadUserValues(String entityName, User user) {
if (user.getId() == null) return Collections.EMPTY_SET;
List<WikiPreferenceValue> values =
entityManager.createQuery(
"select wp from WikiPreferenceValue wp" +
" where wp.entityName = :name and wp.user = :user"
).setParameter("name", entityName)
.setParameter("user", user)
.setHint("org.hibernate.cacheable", true)
.getResultList();
setPropertyReferences(values, entityName, PreferenceVisibility.USER);
return new HashSet(values);
}

private Set<PreferenceValue> loadInstanceValues(String entityName, WikiPluginMacro instance) {
Set<PreferenceValue> valueHolders = new HashSet<PreferenceValue>();
PreferenceEntity preferenceEntity = preferenceRegistry.getPreferenceEntitiesByName().get(entityName);
for (Map.Entry<String, String> entry : instance.getParams().entrySet()) {
log.trace("converting WikiMacro parameter into WikiPreferenceValue: " + entry.getKey());

// TODO: Maybe we should log the following as DEBUG level, these occur when the user edits macro parameters

PreferenceEntity.Property property = preferenceEntity.getPropertiesByName().get(entry.getKey());
if (property == null) {
log.info("can't convert unknown property as WikiMacro parameter: " + entry.getKey());
continue;
}
if (!property.getVisibility().contains(PreferenceVisibility.INSTANCE)) {
log.info("can't convert WikiMacro parameter, not overridable at INSTANCE level: " + entry.getKey());
continue;
}
if (!instance.getMetadata().getParameters().contains(property)) {
log.info("can't convert WikiMacro parameter, property is not configured: " + entry.getKey());
continue;
}
WikiPreferenceValue value = new WikiPreferenceValue(property, entry.getValue());
if (value.getValue() != null) {
log.trace("converted WikiMacro parameter value into WikiPreferenceValue: " + value.getValue());
valueHolders.add(value);
} else {
log.info("could not convert WikiMacro parameter value into WikiPreferenceValue: " + entry.getKey());
}
}
return valueHolders;
}

private void setPropertyReferences(List<WikiPreferenceValue> valueHolders, String entityName, PreferenceVisibility visibility) {
Iterator<WikiPreferenceValue> it = valueHolders.iterator();
while (it.hasNext()) {
WikiPreferenceValue wikiPreferenceValue = it.next();
if (!setPropertyReference(wikiPreferenceValue, entityName, visibility)) {
it.remove(); // Kick out the value if we couldn't set a reference to the metamodel property
}
}
}

private boolean setPropertyReference(WikiPreferenceValue value, String entityName, PreferenceVisibility visibility) {
PreferenceEntity entity = preferenceRegistry.getPreferenceEntitiesByName().get(entityName);
if (entity == null) {
log.warn("orphaned preference value found in database, please clean up: " + value);
return false;
}
PreferenceEntity.Property property = entity.getPropertiesByName().get(value.getPropertyName());
if (property == null) {
log.warn("orphaned preference value found in database, please clean up: " + value);
return false;
}
if (!property.getVisibility().contains(visibility)) {
log.warn("database visibility " + visibility + " is not allowed by property, please clean up: " + value);
return false;
}
value.setPreferenceProperty(property);
return true;
}


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值