/src/metaui/ariba/ui/meta/editor/OSSWriter.java
Java | 473 lines | 399 code | 47 blank | 27 comment | 98 complexity | bd5ac8b011b160f3170729298e0de7b7 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, LGPL-2.1
- /*
- Copyright 2008 Craig Federighi
- 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 ariba.ui.meta.editor;
- import ariba.util.core.ClassExtension;
- import ariba.util.core.ClassExtensionRegistry;
- import ariba.util.core.StringUtil;
- import ariba.util.core.Fmt;
- import ariba.util.core.ListUtil;
- import ariba.util.core.MapUtil;
- import ariba.util.fieldvalue.FieldPath;
- import ariba.ui.meta.core.Meta;
- import ariba.ui.meta.core.Rule;
- import ariba.ui.meta.core.UIMeta;
- import ariba.ui.meta.core.PropertyValue;
- import ariba.ui.aribaweb.util.AWUtil;
- import java.util.Map;
- import java.util.List;
- import java.util.Iterator;
- import java.util.HashMap;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Comparator;
- import java.io.PrintWriter;
- import java.io.StringWriter;
- import java.io.File;
- public class OSSWriter
- {
- protected static final ClassExtensionRegistry
- _ClassExtensionRegistry = new ClassExtensionRegistry();
- static {
- _ClassExtensionRegistry.registerClassExtension(Object.class,
- new OSSSerialize());
- _ClassExtensionRegistry.registerClassExtension(String.class,
- new FromString());
- _ClassExtensionRegistry.registerClassExtension(Number.class,
- new AsToString());
- _ClassExtensionRegistry.registerClassExtension(PropertyValue.Expr.class,
- new AsToString());
- _ClassExtensionRegistry.registerClassExtension(Map.class,
- new FromMap());
- _ClassExtensionRegistry.registerClassExtension(List.class,
- new FromList());
- _ClassExtensionRegistry.registerClassExtension(Meta.OverrideValue.class,
- new FromOverride());
- _ClassExtensionRegistry.registerClassExtension(FieldPath.class,
- new FromFieldPath());
- }
- public static void updateEditorRules (File file, List<Rule> rules)
- {
- StringWriter swriter = new StringWriter();
- PrintWriter writer = new PrintWriter(swriter);
- OSSWriter.RuleNode root = new OSSWriter.RuleNode();
- // Lame version for now. In future, create tree by common properties
- for (Rule rule : rules) {
- root.addRule(rule);
- }
- root.write(writer, 0, true);
- writer.flush();
- updateEditorRules(file, swriter.toString());
- }
- static void updateEditorRules (File file, String updatedRuleText)
- {
- String ruleFileString = AWUtil.stringWithContentsOfFile(file);
- int sepStart = ruleFileString.indexOf(Meta.RuleFileDelimeterStart);
- String userRules = (sepStart == -1) ? ruleFileString : ruleFileString.substring(0, sepStart);
- if (!userRules.endsWith("\n\n\n")) userRules += "\n\n\n";
- String newRules = userRules + Meta.RuleFileDelimeter + updatedRuleText;
- AWUtil.writeToFile(newRules, file);
- }
-
- public static void write (Object obj, PrintWriter writer)
- {
- if (obj != null) {
- OSSSerialize.get(obj).writeOSS(obj, writer);
- } else {
- writer.write("null");
- }
- }
- public static String toOSS (Object obj)
- {
- StringWriter swriter = new StringWriter();
- PrintWriter writer = new PrintWriter(swriter);
- write(obj, writer);
- writer.flush();
- return swriter.toString();
- }
- /*
- Escape user-entered string for parser
- */
- public static String escapeString (String str)
- {
- // Auto-quote casual strings, while not quoting expressions, etc
- if (StringUtil.nullOrEmptyString(str)) return "\"\"";
- if (isKeyPathIdentifier(str)) return str;
- // Don't quote expressions / collections, or already quoted strings
- if ("${[\"\'".indexOf(str.charAt(0)) != -1) return str;
- // don't quote Override values
- if (str.charAt(str.length()-1) == '!' && isKeyPathIdentifier(str.substring(0, str.length()-1))) {
- return str;
- }
- return Fmt.S("\"%s\"", str);
- }
- public static boolean isKeyPathIdentifier (String s) {
- int c = s.length();
- if (c == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) return false;
- for (int i=1; i<c; i++) {
- char ch = s.charAt(i);
- if (!Character.isJavaIdentifierPart(ch) && (ch != '.')) return false;
- }
- return true;
- }
- public static class OSSSerialize extends ClassExtension
- {
- public static OSSSerialize get (Object target)
- {
- return (OSSSerialize)_ClassExtensionRegistry.get(target);
- }
- /*
- Class extension method to format object in OSS
- */
- public void writeOSS (Object value, PrintWriter writer)
- {
- writer.print("null");
- }
- }
- static class FromString extends OSSSerialize
- {
- public void writeOSS (Object value, PrintWriter writer)
- {
- if (!isKeyPathIdentifier((String)value)) {
- writer.print("\"");
- writer.print((String)value);
- writer.print("\"");
- } else {
- writer.print(value);
- }
- }
- }
- static class AsToString extends OSSSerialize
- {
- public void writeOSS (Object value, PrintWriter writer)
- {
- writer.print(value);
- }
- }
- static class FromMap extends OSSSerialize
- {
- public void writeOSS (Object value, PrintWriter writer)
- {
- writer.print("{");
- boolean first = true;
- for (Map.Entry e : ((Map<String, Object>)value).entrySet()) {
- if (first) {
- first = false;
- } else {
- writer.print("; ");
- }
- writer.print(e.getKey());
- writer.print(":");
- write(e.getValue(), writer);
- }
- writer.print("}");
- }
- }
- static class FromList extends OSSSerialize
- {
- public void writeOSS (Object value, PrintWriter writer)
- {
- writer.print("[");
- boolean first = true;
- for (Object v : ((List<Object>)value)) {
- if (first) {
- first = false;
- } else {
- writer.print(", ");
- }
- write(v, writer);
- }
- writer.print("]");
- }
- }
- static class FromOverride extends OSSSerialize
- {
- public void writeOSS (Object value, PrintWriter writer)
- {
- write(((Meta.OverrideValue)value).value(), writer);
- writer.print("!");
- }
- }
- static class FromFieldPath extends OSSSerialize
- {
- public void writeOSS (Object value, PrintWriter writer)
- {
- writer.print("$");
- writer.print(((FieldPath)value).toString());
- }
- }
- static void indent (PrintWriter writer, int level)
- {
- while (level-- > 0) {
- writer.print(" ");
- }
- }
- public static void writeProperties (PrintWriter writer, Map<String, Object> properties, int level, boolean singleLine)
- {
- for (Map.Entry<String,Object> e : properties.entrySet()) {
- if (!singleLine) indent(writer, level);
- Object val = e.getValue();
- if (val == null) {
- writer.printf("%s:null%s", e.getKey(), singleLine ? "; " : ";\n");
- } else {
- OSSSerialize serializer = OSSSerialize.get(val);
- if (serializer.getClass() != OSSSerialize.class) {
- writer.printf("%s:", e.getKey());
- serializer.writeOSS(val, writer);
- writer.print( singleLine ? "; " : ";\n");
- }
- }
- }
- }
- static class RuleNode
- {
- Rule.Selector _selector;
- Map<String, Object> _properties;
- List<RuleNode> _children;
- RuleNode nodeForSelector (Rule.Selector pred)
- {
- if (Meta.isPropertyScopeKey(pred.getKey())) return this;
- if (_children == null) _children = ListUtil.list();
- for (RuleNode node : _children) {
- Rule.Selector nodeP = node._selector;
- if (nodeP.getKey().equals(pred.getKey()) && nodeP.getValue().equals(pred.getValue())) return node;
- }
- RuleNode node = new RuleNode();
- node._selector = pred;
- _children.add(node);
- return node;
- }
- void addRule (Rule rule)
- {
- addRule(rule.getSelectors().listIterator(), rule);
- }
- void addRule (Iterator<Rule.Selector> preds, Rule rule)
- {
- if (preds.hasNext()) {
- nodeForSelector(preds.next()).addRule(preds, rule);
- } else {
- if (_properties == null) _properties = new HashMap();
- Rule.merge(UIMeta.getInstance(), rule.getProperties(), _properties, null, null);
- }
- }
- void write (PrintWriter writer, int level, boolean isRoot)
- {
- int childCount = (_children == null) ? 0 : _children.size();
- boolean hasBlock = !isRoot && ((childCount > 1)
- || (_properties != null && (!shouldInlineProperties(_properties) || childCount > 0)));
- if (_selector != null) {
- writer.printf("%s", _selector.getKey());
- if (!_selector.getValue().equals(Meta.KeyAny) && !_selector.getValue().equals(true)) {
- writer.print("=");
- OSSWriter.write(_selector.getValue(), writer);
- }
- writer.print(" ");
- }
- if (hasBlock) {
- writer.println("{");
- level++;
- }
- if (_children != null) {
- List <RuleNode> children = _children;
- boolean shouldWriteSeparatorNewLine = false;
- if (children.size() > 1) {
- List<RuleNode>predNodes = ListUtil.list();
- List<RuleNode>strippedChildren = ListUtil.list();
- factorPredecessorRules(_children, predNodes, strippedChildren);
- if (predNodes.size() > 1) {
- writePredecessorChain(writer, predNodes, level);
- // write the stripped children
- children = strippedChildren;
- shouldWriteSeparatorNewLine = true;
- }
- }
- for (RuleNode child : children) {
- if (child._properties != null || child._children != null) {
- if (shouldWriteSeparatorNewLine) {
- writer.println();
- shouldWriteSeparatorNewLine = false;
- }
- if (hasBlock) indent(writer, level);
- child.write(writer, level, false);
- }
- }
- }
- if (_properties != null) {
- if (!hasBlock) writer.print(" { ");
- writeProperties (writer, _properties, level, !hasBlock);
- if (!hasBlock) writer.println(" }");
- }
- if (hasBlock) {
- level--;
- indent(writer, level);
- writer.println("}");
- }
- }
- boolean shouldInlineProperties (Map<String, Object> properties) {
- int count = properties.size();
- if (count <= 1) return true;
- if (count == 2) {
- for (Object v : properties.values()) {
- if (v instanceof Collection) return false;
- }
- return true;
- }
- return false;
- }
- void writePredecessorChain (PrintWriter writer, List<RuleNode>predNodes, int level)
- {
- Map<String, List<RuleNode>> predecessors = AWUtil.groupBy(predNodes,
- new AWUtil.ValueMapper() {
- public Object valueForObject(Object o) {
- return ((RuleNode)o)._properties.get(UIMeta.KeyAfter);
- }
- });
- Map<String, List<RuleNode>> nodesByKey = AWUtil.groupBy(predNodes,
- new AWUtil.ValueMapper() {
- public Object valueForObject(Object o) {
- return ((RuleNode)o)._selector.getValue();
- }
- });
- for (String key : ListUtil.collectionToList(predecessors.keySet())) {
- if (predecessors.containsKey(key)) {
- List<RuleNode>newList = ListUtil.list();
- collapseInto(predecessors, key, newList);
- if (!newList.isEmpty()) predecessors.put(key, newList);
- }
- }
- List<String>predKeys = new ArrayList(predecessors.keySet());
- Collections.sort(predKeys, new Comparator() {
- public int compare (Object o1, Object o2)
- {
- int o1Rank = rankForKey(o1);
- int o2Rank = rankForKey(o2);
- return (o1Rank < 99 || o2Rank < 99) ? (o1Rank - o2Rank) : ((Comparable)o1).compareTo(o2);
- }
- });
- for (String predKey : predKeys) {
- indent(writer, level);
- RuleNode pred = (RuleNode)nodesByKey.get(predKey);
- String predTrait = (pred != null) ? (String)pred._properties.get(Meta.KeyTrait) : null;
- writer.print(formatKeyAndTrait(predKey, predTrait));
- for (RuleNode node : predecessors.get(predKey)) {
- writer.printf(" => %s", formatKeyAndTrait((String)node._selector.getValue(),
- node._properties.get(Meta.KeyTrait)));
- }
- writer.println(";");
- }
- }
- static void factorPredecessorRules (List<RuleNode> children, List<RuleNode>predNodes,
- List<RuleNode>otherNodes)
- {
- for (RuleNode node : children) {
- if (node._properties != null && node._properties.containsKey(UIMeta.KeyAfter)) {
- Map predProps = AWUtil.map(UIMeta.KeyAfter, node._properties.get(UIMeta.KeyAfter));
- Map otherProps = MapUtil.cloneMap(node._properties);
- otherProps.remove(UIMeta.KeyAfter);
- Object trait = node._properties.get(Meta.KeyTrait);
- if (trait != null) {
- predProps.put(Meta.KeyTrait, trait);
- otherProps.remove(Meta.KeyTrait);
- }
- RuleNode predNode = new RuleNode();
- predNode._selector = node._selector;
- predNode._properties = predProps;
- predNodes.add(predNode);
- RuleNode otherNode = new RuleNode();
- otherNode._selector = node._selector;
- otherNode._properties = (otherProps.size() > 0) ? otherProps : null;
- otherNode._children = node._children;
- otherNodes.add(otherNode);
- } else {
- otherNodes.add(node);
- }
- }
- }
- static Map _PredKeyRank = AWUtil.map("zNone", 0, "zMain", 1, "zTop", 2,
- "zLeft", 3, "zRight", 4, "zBottom", 5, "zDetail", 6);
- static int rankForKey (Object k)
- {
- Object r = _PredKeyRank.get(k);
- return (r == null) ? 1000 : ((Number)r).intValue();
- }
- void collapseInto (Map<String, List<RuleNode>> predecessors, String key, List<RuleNode> result)
- {
- List<RuleNode> followers = predecessors.get(key);
- if (followers != null) {
- predecessors.remove(key);
- for (RuleNode node : followers) {
- result.add(node);
- String followerKey = (String)node._selector.getValue();
- collapseInto(predecessors, followerKey, result);
- }
- }
- }
- static String formatKeyAndTrait (String key, Object traits)
- {
- if (traits == null) return key;
- String traitString = (traits instanceof String) ? (String)traits
- : StringUtil.join((List)traits,",");
- return Fmt.S("%s#%s", key, traitString);
- }
- }
- }