/*
* Copyright (C) NetStruxr, Inc. All rights reserved.
*
* This software is published under the terms of the NetStruxr
* Public Software License version 0.5, a copy of which has been
* included with this distribution in the LICENSE.NPL file. */
package er.directtoweb;
import java.util.Enumeration;
import org.apache.log4j.Logger;
import com.webobjects.directtoweb.Assignment;
import com.webobjects.directtoweb.BooleanAssignment;
import com.webobjects.directtoweb.D2WContext;
import com.webobjects.directtoweb.ERD2WContext;
import com.webobjects.directtoweb.Rule;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSBundle;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSPropertyListSerialization;
import er.extensions.foundation.ERXDictionaryUtilities;
/**
* Converts given entries of a D2WContext with a specified page configuration to a dictionary and to rules again.<br>
* Very useful for debugging and testing. You can effectively dump a context for a given page configuration
* into a <code>.plist</code> file once you are content with your page, then make tons of changes to the rules
* and all the while test the changed value against all your stored dictionaries, which should make you
* more confident to make changes like <code>*true* => componentName = "D2WString" [100]</code><br>
* Also, given a dictionary, you can re-create the rules for creating these entries with any given level.<br>
* Reads in your <code>d2wclientConfiguration.plists</code> files from every bundle and also reads in the values
* given in the <code>editors</code> and <code>supports</code> fields.<br>
* So be sure to keep the entries to those files up to date :)
<pre><code>
NSArray pageKeys = new NSArray(new Object [] {"pageWrapperName", "pageName", "headComponentName", "displayPropertyKeys"});
NSArray componentKeys = new NSArray(new Object [] {"componentName", "customComponentName"});
ERD2WContextDictionary dict = new ERD2WContextDictionary("CreateModuleGroup", pageKeys, componentKeys);
String value = NSPropertyListSerialization.stringFromPropertyList(dict.dictionary());
</code></pre>
* RENAMEME: to something more sensible??
* @author ak
*/
public class ERD2WContextDictionary {
private static final Logger log = Logger.getLogger(ERD2WContextDictionary.class);
public static class Configuration {
private NSMutableDictionary components = new NSMutableDictionary();
private NSMutableDictionary editors = new NSMutableDictionary();
public Configuration() {
NSMutableArray bundles = NSBundle.frameworkBundles().mutableClone();
bundles.addObject(NSBundle.mainBundle());
for(Enumeration e = bundles.objectEnumerator(); e.hasMoreElements(); ) {
NSBundle bundle = (NSBundle)e.nextElement();
NSDictionary dict;
String path = bundle.resourcePathForLocalizedResourceNamed("d2wclientConfiguration.plist", null);
if(path != null) {
dict = ERXDictionaryUtilities.dictionaryFromPropertyList("d2wclientConfiguration", bundle);
if(dict != null) {
if(dict.objectForKey("components") != null) {
components.addEntriesFromDictionary((NSDictionary)dict.objectForKey("components"));
}
if(dict.objectForKey("editors") != null) {
editors.addEntriesFromDictionary((NSDictionary)dict.objectForKey("editors"));
}
}
}
}
}
public NSMutableDictionary components() {
return components;
}
public NSMutableDictionary editors() {
return editors;
}
}
protected D2WContext _context;
protected String _pageConfiguration;
protected NSMutableArray _pageLevelKeys;
protected NSMutableArray _componentLevelKeys;
protected NSMutableDictionary _dictionary;
protected NSMutableDictionary _allKeys;
public ERD2WContextDictionary(String pageConfigurationName, NSArray pageKeys, NSArray componentKeys) {
_pageConfiguration = pageConfigurationName;
_context = ERD2WContext.newContext();
_context.setDynamicPage(_pageConfiguration);
_context.setTask(_context.task());
_context.setEntity(_context.entity());
if(pageKeys == null) {
_pageLevelKeys = new NSMutableArray(new Object[] {"pageWrapperName", "displayPropertyKeys", "pageName"});
} else {
_pageLevelKeys = pageKeys.mutableClone();
}
NSArray keys = new NSMutableArray(new Object[] {"componentName", "customComponentName",
"displayNameForProperty", "propertyKey"});
_componentLevelKeys = new NSMutableArray();
if(componentKeys != null) {
_componentLevelKeys = componentKeys.mutableClone();
}
for(Enumeration e = keys.objectEnumerator(); e.hasMoreElements(); ) {
String key = (String)e.nextElement();
if(!_componentLevelKeys.containsObject(key)) {
_componentLevelKeys.addObject(key);
}
}
if("edit".equals(_context.task())) {
_componentLevelKeys.addObject("isMandatory");
}
if("list".equals(_context.task())) {
_componentLevelKeys.addObject("propertyIsSortable");
_componentLevelKeys.addObject("sortKeyForList");
}
_allKeys = new NSMutableDictionary();
Configuration config = new Configuration();
_allKeys.setObjectForKey(config.components(), "components");
_allKeys.setObjectForKey(config.editors(), "editors");
}
public ERD2WContextDictionary(String pageConfiguration, NSDictionary dictionary) {
_pageConfiguration = pageConfiguration;
_dictionary = dictionary.mutableClone();
}
protected void addPageLevelValues() {
for(Enumeration e = _pageLevelKeys.objectEnumerator(); e.hasMoreElements(); ) {
String key = (String)e.nextElement();
Object o = _context.valueForKey(key);
if(o != null)
_dictionary.takeValueForKey(o, key);
}
String path = "components." + _context.valueForKey("pageName") + ".editors";
NSArray keys = (NSArray)_allKeys.valueForKeyPath(path);
if(keys != null) {
for(Enumeration e = keys.objectEnumerator(); e.hasMoreElements(); ) {
String key = (String)e.nextElement();
Object o = _context.valueForKey(key);
if(o != null)
_dictionary.takeValueForKeyPath(o, key);
}
}
path = "components." + _context.valueForKey("pageName") + ".supports";
keys = (NSArray)_allKeys.valueForKeyPath(path);
if(keys != null) {
for(Enumeration e = keys.objectEnumerator(); e.hasMoreElements(); ) {
String key = (String)e.nextElement();
Object o = _context.valueForKey(key);
if(o != null)
_dictionary.takeValueForKeyPath(o, key);
}
}
}
/**
* Returns the keys for the given property key. To find which keys are
* requiered, the componentName key is used to get the editors and supports.
* @param propertyKey
*/
protected NSDictionary componentLevelValuesForKey(String propertyKey) {
_context.setPropertyKey(propertyKey);
NSMutableDictionary dictionary = new NSMutableDictionary();
for(Enumeration e = _componentLevelKeys.objectEnumerator(); e.hasMoreElements(); ) {
String key = (String)e.nextElement();
Object o = _context.valueForKey(key);
if(o != null)
dictionary.setObjectForKey(o, key);
}
String path = "components." + dictionary.objectForKey("componentName") + ".editors";
NSArray keys = (NSArray)_allKeys.valueForKeyPath(path);
if(keys != null) {
for(Enumeration e = keys.objectEnumerator(); e.hasMoreElements(); ) {
String key = (String)e.nextElement();
Object o = _context.valueForKey(key);
if(o != null)
dictionary.setObjectForKey(o, key);
}
}
path = "components." + dictionary.objectForKey("componentName") + ".supports";
keys = (NSArray)_allKeys.valueForKeyPath(path);
if(keys != null) {
for(Enumeration e = keys.objectEnumerator(); e.hasMoreElements(); ) {
String key = (String)e.nextElement();
Object o = _context.valueForKey(key);
if(o != null)
dictionary.setObjectForKey(o, key);
}
}
_context.setPropertyKey(null);
return dictionary;
}
public NSDictionary dictionary() {
if(_dictionary == null) {
_dictionary = new NSMutableDictionary();
addPageLevelValues();
NSArray displayPropertyKeys = (NSArray)_context.valueForKey("displayPropertyKeys");
if(displayPropertyKeys != null && displayPropertyKeys.count() > 0) {
NSMutableDictionary componentLevelKeys = new NSMutableDictionary();
addPropertyKeys(componentLevelKeys, displayPropertyKeys);
_dictionary.setObjectForKey( componentLevelKeys, "componentLevelKeys");
}
}
return _dictionary;
}
protected void addPropertyKeys(NSMutableDictionary componentLevelKeys, NSArray array) {
for(Enumeration e = array.objectEnumerator(); e.hasMoreElements(); ) {
Object o = e.nextElement();
if(o instanceof NSArray) {
addPropertyKeys(componentLevelKeys, (NSArray)o);
} else {
String key = (String)o;
componentLevelKeys.setObjectForKey(componentLevelValuesForKey(key), key);
}
}
}
public NSArray rulesForLevel(int level) {
NSMutableArray arr = new NSMutableArray();
for(Enumeration e = dictionary().keyEnumerator(); e.hasMoreElements(); ) {
String key = (String)e.nextElement();
if(!"componentLevelKeys".equals(key)) {
Object value = dictionary().valueForKey(key);
EOQualifier q = EOQualifier.qualifierWithQualifierFormat( "pageConfiguration = '" + _pageConfiguration + "'" , null);
Assignment a = createAssigment(key, value);
arr.addObject(new Rule(level, q, a));
}
}
NSArray keys = (NSArray)_dictionary.valueForKey("displayPropertyKeys");
if(keys != null && keys.count() > 0) {
addRulesForPropertyKeys(level, arr, keys);
}
return arr;
}
private Assignment createAssigment(String key, Object value) {
Assignment a;
if("true".equals(value) || "false".equals(value)) {
a = new BooleanAssignment(key, value);
} else {
a = new Assignment(key, value);
}
return a;
}
protected void addRulesForPropertyKeys(int level, NSMutableArray rules, NSArray keys) {
for(Enumeration e = keys.objectEnumerator(); e.hasMoreElements(); ) {
Object o = e.nextElement();
if(o instanceof NSArray) {
addRulesForPropertyKeys(level, rules, keys);
} else {
String propertyKey = (String)o;
NSDictionary values = (NSDictionary)dictionary().valueForKeyPath("componentLevelKeys." + propertyKey);
EOQualifier q = EOQualifier.qualifierWithQualifierFormat( "pageConfiguration = '" + _pageConfiguration + "' and propertyKey = '" + propertyKey + "'" , null);
for (Enumeration e1 = values.keyEnumerator(); e1.hasMoreElements();) {
String key = (String)e1.nextElement();
Object value = values.objectForKey(key);
Assignment a = createAssigment(key, value);
rules.addObject(new Rule(level, q, a));
}
}
}
}
public D2WContext context() {
return _context;
}
public String dictionaryString() {
return NSPropertyListSerialization.stringFromPropertyList(dictionary());
}
@Override
public String toString() {
return context() + ": " + dictionaryString();
}
}