`AbstractGriffonView.java`
`001 /* 002 * Copyright 2010-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.codehaus.griffon.runtime.core; 018 019 import griffon.core.GriffonView; 020 import griffon.core.GriffonViewClass; 021 import griffon.util.Xml2Groovy; 022 import groovy.lang.GroovyShell; 023 import groovy.lang.Script; 024 import groovy.util.FactoryBuilderSupport; 025 026 import java.io.InputStream; 027 import java.util.Map; 028 029 import static griffon.util.GriffonNameUtils.isBlank; 030 031 /** 032 * Base implementation of the GriffonView interface. 033 * 034 * @author Andres Almiray 035 * @since 0.9.1 036 */ 037 public abstract class AbstractGriffonView extends AbstractGriffonMvcArtifact implements GriffonView { 038 private FactoryBuilderSupport builder; 039 040 protected String getArtifactType() { 041 return GriffonViewClass.TYPE; 042 } 043 044 public FactoryBuilderSupport getBuilder() { 045 return builder; 046 } 047 048 public void setBuilder(FactoryBuilderSupport builder) { 049 this.builder = builder; 050 } 051 052 /** 053 * Transforms an XML file into a Groovy script and evaluates it using a builder.</p> 054 * <p>The file name matches the name of this class plus '.xml'. It must be found somewhere 055 * in the classpath.</p> 056 * <p>Every XML attribute that represents a string literal must be single quoted explicitly 057 * otherwise the build will not be able to parse it. The following XML contents</p> 058 * <pre><xmp> 059 * <application title="app.config.application.title" 060 * pack="true"> 061 * <actions> 062 * <action id="'clickAction'" 063 * name="'Click'" 064 * closure="{controller.click(it)}"/> 065 * </actions> 066 * <gridLayout cols="1" rows="3"/> 067 * <textField id="'input'" columns="20" 068 * text="bind('value', target: model)"/> 069 * <textField id="'output'" columns="20" 070 * text="bind{model.value}" editable="false"/> 071 * <button action="clickAction"/> 072 * </application> 073 * </xmp></pre> 074 * <p/> 075 * <p>are translated to</p> 076 * <pre> 077 * application(title: app.config.application.title, pack: true) { 078 * actions { 079 * action(id: 'clickAction', name: 'Click', closure: {controller.click(it)}) 080 * } 081 * gridLayout(cols: 1, rows: 3) 082 * textField(id: 'input', text: bind('value', target: model), columns: 20) 083 * textField(id: 'output', text: bind{target.model}, columns: 20, editable: false) 084 * button(action: clickAction) 085 * } 086 * </pre> 087 * 088 * @param args a Map containing all relevant values that the build might need to build the 089 * View; this typically includes 'app', 'controller' and 'model'. 090 * @since 0.9.2 091 */ 092 public void buildViewFromXml(Map<String, Object> args) { 093 buildViewFromXml(args, getClass().getName().replace('.', '/') + ".xml"); 094 } 095 096 /** 097 * Transforms an XML file into a Groovy script and evaluates it using a builder.</p> 098 * <p>Every XML attribute that represents a string literal must be single quoted explicitly 099 * otherwise the build will not be able to parse it. The following XML contents</p> 100 * <pre><xmp> 101 * <application title="app.config.application.title" 102 * pack="true"> 103 * <actions> 104 * <action id="'clickAction'" 105 * name="'Click'" 106 * closure="{controller.click(it)}"/> 107 * </actions> 108 * <gridLayout cols="1" rows="3"/> 109 * <textField id="'input'" columns="20" 110 * text="bind('value', target: model)"/> 111 * <textField id="'output'" columns="20" 112 * text="bind{model.value}" editable="false"/> 113 * <button action="clickAction"/> 114 * </application> 115 * </xmp></pre> 116 * <p/> 117 * <p>are translated to</p> 118 * <pre> 119 * application(title: app.config.application.title, pack: true) { 120 * actions { 121 * action(id: 'clickAction', name: 'Click', closure: {controller.click(it)}) 122 * } 123 * gridLayout(cols: 1, rows: 3) 124 * textField(id: 'input', text: bind('value', target: model), columns: 20) 125 * textField(id: 'output', text: bind{target.model}, columns: 20, editable: false) 126 * button(action: clickAction) 127 * } 128 * </pre> 129 * 130 * @param args a Map containing all relevant values that the build might need to build the 131 * View; this typically includes 'app', 'controller' and 'model'. 132 * @param fileName the name of an XML file 133 * @since 0.9.2 134 */ 135 public void buildViewFromXml(Map<String, Object> args, String fileName) { 136 if (isBlank(fileName)) { 137 throw new IllegalArgumentException("Invalid file name for externalized view."); 138 } 139 140 InputStream is = getClass().getClassLoader().getResourceAsStream(fileName); 141 if (is == null) { 142 throw new IllegalArgumentException("Could not read file " + fileName); 143 } 144 145 String groovyScript = Xml2Groovy.getInstance().parse(is); 146 if (isBlank(groovyScript)) { 147 throw new IllegalArgumentException("File " + fileName + " is empty."); 148 } else if (getLog().isTraceEnabled()) { 149 getLog().trace("View script for " + fileName + "\n" + groovyScript); 150 } 151 152 final Script script = new GroovyShell().parse(groovyScript); 153 script.setBinding(getBuilder()); 154 for (Map.Entry<String, ?> arg : args.entrySet()) { 155 script.getBinding().setVariable(arg.getKey(), arg.getValue()); 156 } 157 158 getApp().execSync(new Runnable() { 159 public void run() { 160 getBuilder().build(script); 161 } 162 }); 163 } 164 }`