PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/metaui/ariba/ui/meta/editor/OSSWriter.java

http://aribaweb.googlecode.com/
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
  1. /*
  2. Copyright 2008 Craig Federighi
  3. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
  4. file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. $ $
  13. */
  14. package ariba.ui.meta.editor;
  15. import ariba.util.core.ClassExtension;
  16. import ariba.util.core.ClassExtensionRegistry;
  17. import ariba.util.core.StringUtil;
  18. import ariba.util.core.Fmt;
  19. import ariba.util.core.ListUtil;
  20. import ariba.util.core.MapUtil;
  21. import ariba.util.fieldvalue.FieldPath;
  22. import ariba.ui.meta.core.Meta;
  23. import ariba.ui.meta.core.Rule;
  24. import ariba.ui.meta.core.UIMeta;
  25. import ariba.ui.meta.core.PropertyValue;
  26. import ariba.ui.aribaweb.util.AWUtil;
  27. import java.util.Map;
  28. import java.util.List;
  29. import java.util.Iterator;
  30. import java.util.HashMap;
  31. import java.util.ArrayList;
  32. import java.util.Collection;
  33. import java.util.Collections;
  34. import java.util.Comparator;
  35. import java.io.PrintWriter;
  36. import java.io.StringWriter;
  37. import java.io.File;
  38. public class OSSWriter
  39. {
  40. protected static final ClassExtensionRegistry
  41. _ClassExtensionRegistry = new ClassExtensionRegistry();
  42. static {
  43. _ClassExtensionRegistry.registerClassExtension(Object.class,
  44. new OSSSerialize());
  45. _ClassExtensionRegistry.registerClassExtension(String.class,
  46. new FromString());
  47. _ClassExtensionRegistry.registerClassExtension(Number.class,
  48. new AsToString());
  49. _ClassExtensionRegistry.registerClassExtension(PropertyValue.Expr.class,
  50. new AsToString());
  51. _ClassExtensionRegistry.registerClassExtension(Map.class,
  52. new FromMap());
  53. _ClassExtensionRegistry.registerClassExtension(List.class,
  54. new FromList());
  55. _ClassExtensionRegistry.registerClassExtension(Meta.OverrideValue.class,
  56. new FromOverride());
  57. _ClassExtensionRegistry.registerClassExtension(FieldPath.class,
  58. new FromFieldPath());
  59. }
  60. public static void updateEditorRules (File file, List<Rule> rules)
  61. {
  62. StringWriter swriter = new StringWriter();
  63. PrintWriter writer = new PrintWriter(swriter);
  64. OSSWriter.RuleNode root = new OSSWriter.RuleNode();
  65. // Lame version for now. In future, create tree by common properties
  66. for (Rule rule : rules) {
  67. root.addRule(rule);
  68. }
  69. root.write(writer, 0, true);
  70. writer.flush();
  71. updateEditorRules(file, swriter.toString());
  72. }
  73. static void updateEditorRules (File file, String updatedRuleText)
  74. {
  75. String ruleFileString = AWUtil.stringWithContentsOfFile(file);
  76. int sepStart = ruleFileString.indexOf(Meta.RuleFileDelimeterStart);
  77. String userRules = (sepStart == -1) ? ruleFileString : ruleFileString.substring(0, sepStart);
  78. if (!userRules.endsWith("\n\n\n")) userRules += "\n\n\n";
  79. String newRules = userRules + Meta.RuleFileDelimeter + updatedRuleText;
  80. AWUtil.writeToFile(newRules, file);
  81. }
  82. public static void write (Object obj, PrintWriter writer)
  83. {
  84. if (obj != null) {
  85. OSSSerialize.get(obj).writeOSS(obj, writer);
  86. } else {
  87. writer.write("null");
  88. }
  89. }
  90. public static String toOSS (Object obj)
  91. {
  92. StringWriter swriter = new StringWriter();
  93. PrintWriter writer = new PrintWriter(swriter);
  94. write(obj, writer);
  95. writer.flush();
  96. return swriter.toString();
  97. }
  98. /*
  99. Escape user-entered string for parser
  100. */
  101. public static String escapeString (String str)
  102. {
  103. // Auto-quote casual strings, while not quoting expressions, etc
  104. if (StringUtil.nullOrEmptyString(str)) return "\"\"";
  105. if (isKeyPathIdentifier(str)) return str;
  106. // Don't quote expressions / collections, or already quoted strings
  107. if ("${[\"\'".indexOf(str.charAt(0)) != -1) return str;
  108. // don't quote Override values
  109. if (str.charAt(str.length()-1) == '!' && isKeyPathIdentifier(str.substring(0, str.length()-1))) {
  110. return str;
  111. }
  112. return Fmt.S("\"%s\"", str);
  113. }
  114. public static boolean isKeyPathIdentifier (String s) {
  115. int c = s.length();
  116. if (c == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) return false;
  117. for (int i=1; i<c; i++) {
  118. char ch = s.charAt(i);
  119. if (!Character.isJavaIdentifierPart(ch) && (ch != '.')) return false;
  120. }
  121. return true;
  122. }
  123. public static class OSSSerialize extends ClassExtension
  124. {
  125. public static OSSSerialize get (Object target)
  126. {
  127. return (OSSSerialize)_ClassExtensionRegistry.get(target);
  128. }
  129. /*
  130. Class extension method to format object in OSS
  131. */
  132. public void writeOSS (Object value, PrintWriter writer)
  133. {
  134. writer.print("null");
  135. }
  136. }
  137. static class FromString extends OSSSerialize
  138. {
  139. public void writeOSS (Object value, PrintWriter writer)
  140. {
  141. if (!isKeyPathIdentifier((String)value)) {
  142. writer.print("\"");
  143. writer.print((String)value);
  144. writer.print("\"");
  145. } else {
  146. writer.print(value);
  147. }
  148. }
  149. }
  150. static class AsToString extends OSSSerialize
  151. {
  152. public void writeOSS (Object value, PrintWriter writer)
  153. {
  154. writer.print(value);
  155. }
  156. }
  157. static class FromMap extends OSSSerialize
  158. {
  159. public void writeOSS (Object value, PrintWriter writer)
  160. {
  161. writer.print("{");
  162. boolean first = true;
  163. for (Map.Entry e : ((Map<String, Object>)value).entrySet()) {
  164. if (first) {
  165. first = false;
  166. } else {
  167. writer.print("; ");
  168. }
  169. writer.print(e.getKey());
  170. writer.print(":");
  171. write(e.getValue(), writer);
  172. }
  173. writer.print("}");
  174. }
  175. }
  176. static class FromList extends OSSSerialize
  177. {
  178. public void writeOSS (Object value, PrintWriter writer)
  179. {
  180. writer.print("[");
  181. boolean first = true;
  182. for (Object v : ((List<Object>)value)) {
  183. if (first) {
  184. first = false;
  185. } else {
  186. writer.print(", ");
  187. }
  188. write(v, writer);
  189. }
  190. writer.print("]");
  191. }
  192. }
  193. static class FromOverride extends OSSSerialize
  194. {
  195. public void writeOSS (Object value, PrintWriter writer)
  196. {
  197. write(((Meta.OverrideValue)value).value(), writer);
  198. writer.print("!");
  199. }
  200. }
  201. static class FromFieldPath extends OSSSerialize
  202. {
  203. public void writeOSS (Object value, PrintWriter writer)
  204. {
  205. writer.print("$");
  206. writer.print(((FieldPath)value).toString());
  207. }
  208. }
  209. static void indent (PrintWriter writer, int level)
  210. {
  211. while (level-- > 0) {
  212. writer.print(" ");
  213. }
  214. }
  215. public static void writeProperties (PrintWriter writer, Map<String, Object> properties, int level, boolean singleLine)
  216. {
  217. for (Map.Entry<String,Object> e : properties.entrySet()) {
  218. if (!singleLine) indent(writer, level);
  219. Object val = e.getValue();
  220. if (val == null) {
  221. writer.printf("%s:null%s", e.getKey(), singleLine ? "; " : ";\n");
  222. } else {
  223. OSSSerialize serializer = OSSSerialize.get(val);
  224. if (serializer.getClass() != OSSSerialize.class) {
  225. writer.printf("%s:", e.getKey());
  226. serializer.writeOSS(val, writer);
  227. writer.print( singleLine ? "; " : ";\n");
  228. }
  229. }
  230. }
  231. }
  232. static class RuleNode
  233. {
  234. Rule.Selector _selector;
  235. Map<String, Object> _properties;
  236. List<RuleNode> _children;
  237. RuleNode nodeForSelector (Rule.Selector pred)
  238. {
  239. if (Meta.isPropertyScopeKey(pred.getKey())) return this;
  240. if (_children == null) _children = ListUtil.list();
  241. for (RuleNode node : _children) {
  242. Rule.Selector nodeP = node._selector;
  243. if (nodeP.getKey().equals(pred.getKey()) && nodeP.getValue().equals(pred.getValue())) return node;
  244. }
  245. RuleNode node = new RuleNode();
  246. node._selector = pred;
  247. _children.add(node);
  248. return node;
  249. }
  250. void addRule (Rule rule)
  251. {
  252. addRule(rule.getSelectors().listIterator(), rule);
  253. }
  254. void addRule (Iterator<Rule.Selector> preds, Rule rule)
  255. {
  256. if (preds.hasNext()) {
  257. nodeForSelector(preds.next()).addRule(preds, rule);
  258. } else {
  259. if (_properties == null) _properties = new HashMap();
  260. Rule.merge(UIMeta.getInstance(), rule.getProperties(), _properties, null, null);
  261. }
  262. }
  263. void write (PrintWriter writer, int level, boolean isRoot)
  264. {
  265. int childCount = (_children == null) ? 0 : _children.size();
  266. boolean hasBlock = !isRoot && ((childCount > 1)
  267. || (_properties != null && (!shouldInlineProperties(_properties) || childCount > 0)));
  268. if (_selector != null) {
  269. writer.printf("%s", _selector.getKey());
  270. if (!_selector.getValue().equals(Meta.KeyAny) && !_selector.getValue().equals(true)) {
  271. writer.print("=");
  272. OSSWriter.write(_selector.getValue(), writer);
  273. }
  274. writer.print(" ");
  275. }
  276. if (hasBlock) {
  277. writer.println("{");
  278. level++;
  279. }
  280. if (_children != null) {
  281. List <RuleNode> children = _children;
  282. boolean shouldWriteSeparatorNewLine = false;
  283. if (children.size() > 1) {
  284. List<RuleNode>predNodes = ListUtil.list();
  285. List<RuleNode>strippedChildren = ListUtil.list();
  286. factorPredecessorRules(_children, predNodes, strippedChildren);
  287. if (predNodes.size() > 1) {
  288. writePredecessorChain(writer, predNodes, level);
  289. // write the stripped children
  290. children = strippedChildren;
  291. shouldWriteSeparatorNewLine = true;
  292. }
  293. }
  294. for (RuleNode child : children) {
  295. if (child._properties != null || child._children != null) {
  296. if (shouldWriteSeparatorNewLine) {
  297. writer.println();
  298. shouldWriteSeparatorNewLine = false;
  299. }
  300. if (hasBlock) indent(writer, level);
  301. child.write(writer, level, false);
  302. }
  303. }
  304. }
  305. if (_properties != null) {
  306. if (!hasBlock) writer.print(" { ");
  307. writeProperties (writer, _properties, level, !hasBlock);
  308. if (!hasBlock) writer.println(" }");
  309. }
  310. if (hasBlock) {
  311. level--;
  312. indent(writer, level);
  313. writer.println("}");
  314. }
  315. }
  316. boolean shouldInlineProperties (Map<String, Object> properties) {
  317. int count = properties.size();
  318. if (count <= 1) return true;
  319. if (count == 2) {
  320. for (Object v : properties.values()) {
  321. if (v instanceof Collection) return false;
  322. }
  323. return true;
  324. }
  325. return false;
  326. }
  327. void writePredecessorChain (PrintWriter writer, List<RuleNode>predNodes, int level)
  328. {
  329. Map<String, List<RuleNode>> predecessors = AWUtil.groupBy(predNodes,
  330. new AWUtil.ValueMapper() {
  331. public Object valueForObject(Object o) {
  332. return ((RuleNode)o)._properties.get(UIMeta.KeyAfter);
  333. }
  334. });
  335. Map<String, List<RuleNode>> nodesByKey = AWUtil.groupBy(predNodes,
  336. new AWUtil.ValueMapper() {
  337. public Object valueForObject(Object o) {
  338. return ((RuleNode)o)._selector.getValue();
  339. }
  340. });
  341. for (String key : ListUtil.collectionToList(predecessors.keySet())) {
  342. if (predecessors.containsKey(key)) {
  343. List<RuleNode>newList = ListUtil.list();
  344. collapseInto(predecessors, key, newList);
  345. if (!newList.isEmpty()) predecessors.put(key, newList);
  346. }
  347. }
  348. List<String>predKeys = new ArrayList(predecessors.keySet());
  349. Collections.sort(predKeys, new Comparator() {
  350. public int compare (Object o1, Object o2)
  351. {
  352. int o1Rank = rankForKey(o1);
  353. int o2Rank = rankForKey(o2);
  354. return (o1Rank < 99 || o2Rank < 99) ? (o1Rank - o2Rank) : ((Comparable)o1).compareTo(o2);
  355. }
  356. });
  357. for (String predKey : predKeys) {
  358. indent(writer, level);
  359. RuleNode pred = (RuleNode)nodesByKey.get(predKey);
  360. String predTrait = (pred != null) ? (String)pred._properties.get(Meta.KeyTrait) : null;
  361. writer.print(formatKeyAndTrait(predKey, predTrait));
  362. for (RuleNode node : predecessors.get(predKey)) {
  363. writer.printf(" => %s", formatKeyAndTrait((String)node._selector.getValue(),
  364. node._properties.get(Meta.KeyTrait)));
  365. }
  366. writer.println(";");
  367. }
  368. }
  369. static void factorPredecessorRules (List<RuleNode> children, List<RuleNode>predNodes,
  370. List<RuleNode>otherNodes)
  371. {
  372. for (RuleNode node : children) {
  373. if (node._properties != null && node._properties.containsKey(UIMeta.KeyAfter)) {
  374. Map predProps = AWUtil.map(UIMeta.KeyAfter, node._properties.get(UIMeta.KeyAfter));
  375. Map otherProps = MapUtil.cloneMap(node._properties);
  376. otherProps.remove(UIMeta.KeyAfter);
  377. Object trait = node._properties.get(Meta.KeyTrait);
  378. if (trait != null) {
  379. predProps.put(Meta.KeyTrait, trait);
  380. otherProps.remove(Meta.KeyTrait);
  381. }
  382. RuleNode predNode = new RuleNode();
  383. predNode._selector = node._selector;
  384. predNode._properties = predProps;
  385. predNodes.add(predNode);
  386. RuleNode otherNode = new RuleNode();
  387. otherNode._selector = node._selector;
  388. otherNode._properties = (otherProps.size() > 0) ? otherProps : null;
  389. otherNode._children = node._children;
  390. otherNodes.add(otherNode);
  391. } else {
  392. otherNodes.add(node);
  393. }
  394. }
  395. }
  396. static Map _PredKeyRank = AWUtil.map("zNone", 0, "zMain", 1, "zTop", 2,
  397. "zLeft", 3, "zRight", 4, "zBottom", 5, "zDetail", 6);
  398. static int rankForKey (Object k)
  399. {
  400. Object r = _PredKeyRank.get(k);
  401. return (r == null) ? 1000 : ((Number)r).intValue();
  402. }
  403. void collapseInto (Map<String, List<RuleNode>> predecessors, String key, List<RuleNode> result)
  404. {
  405. List<RuleNode> followers = predecessors.get(key);
  406. if (followers != null) {
  407. predecessors.remove(key);
  408. for (RuleNode node : followers) {
  409. result.add(node);
  410. String followerKey = (String)node._selector.getValue();
  411. collapseInto(predecessors, followerKey, result);
  412. }
  413. }
  414. }
  415. static String formatKeyAndTrait (String key, Object traits)
  416. {
  417. if (traits == null) return key;
  418. String traitString = (traits instanceof String) ? (String)traits
  419. : StringUtil.join((List)traits,",");
  420. return Fmt.S("%s#%s", key, traitString);
  421. }
  422. }
  423. }