View Javadoc

1   /*
2    * Copyright 2007-2008 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.gwe.integration.slicer;
18  
19  import java.io.FileNotFoundException;
20  import java.io.IOException;
21  import java.rmi.RemoteException;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.gwe.GWEAppContext;
28  import org.gwe.api.ServerAPIConnectionException;
29  import org.gwe.api.Session4ClientAPIEnhancer;
30  import org.gwe.api.event.DefaultEventFilter;
31  import org.gwe.api.exceptions.GWEDomainException;
32  import org.gwe.api.exceptions.PasswordMismatchException;
33  import org.gwe.app.client.ProgressTracker;
34  import org.gwe.app.client.admin.InstallerException;
35  import org.gwe.app.client.config.ClientConfig;
36  import org.gwe.app.client.config.XMLClientConfigReader;
37  import org.gwe.integration.slicer.model.GroupModel;
38  import org.gwe.integration.slicer.model.param.PMEnumString;
39  import org.gwe.integration.slicer.model.param.PMString;
40  import org.gwe.p2elv2.P2ELSyntaxException;
41  import org.gwe.persistence.model.HeadResourceInfo;
42  import org.gwe.persistence.model.OrderInfo;
43  import org.gwe.persistence.model.order.p2el.POrderDescriptor;
44  import org.gwe.utils.IOUtils;
45  import org.gwe.utils.StringUtils;
46  import org.gwe.utils.VelocityUtils;
47  import org.gwe.utils.cmd.ArgsList;
48  import org.gwe.utils.cmd.OptionableAppTemplate;
49  import org.gwe.utils.rex.REXUtils;
50  import org.gwe.utils.security.CredentialNotFoundException;
51  
52  /**
53   * @author Marco Ruiz
54   * @since Jan 15, 2008
55   */
56  public class GWECLMProxyApp extends AbstractCLMProxyApp {
57  
58  	private static Log log = LogFactory.getLog(GWECLMProxyApp.class);
59  	
60  	private static String VAR_SLICER_HOME = "${SLICER_HOME}";
61  	private static String ERROR_FILTER_NAME = "<filter-name>Error Message</filter-name>"; 
62  
63  	public static void main(String[] args) throws Exception { 
64  		proxyAppClassMain(GWECLMProxyApp.class, new ArgsList(args)); 
65  	}
66  	
67  	private OptionableAppTemplate template;
68  	private GroupModel settings;
69  	private PMEnumString optClusterDesc;
70  	private PMString optVariables;
71  
72  	private WrapperCLMProxyApp proxiedModule;
73  
74  	private ClientConfig appConfig;
75  	
76  	private ProgressTracker progressTracker = new ProgressTracker() {
77  		public void trackProgress(String msg) {
78  			msg = "<filter-start>" + ERROR_FILTER_NAME + "<filter-comment>" + msg + "</filter-comment></filter-start>";
79  			msg += "<filter-end>"  + ERROR_FILTER_NAME + "<filter-time>0</filter-time></filter-end>";
80  			System.out.println(msg);
81  			ProgressTracker.CONSOLE_TRACKER.trackProgress(msg);
82          }
83  	};
84  
85  	public GWECLMProxyApp(String proxiedModuleName) throws IOException {
86  		this.proxiedModule = new WrapperCLMProxyApp(proxiedModuleName);
87  		try {
88  	        this.appConfig = new ClientConfig(new XMLClientConfigReader(null));
89  	        this.appConfig.setTracker(progressTracker);
90          } catch (FileNotFoundException e) {
91  	        // TODO Auto-generated catch block
92  	        e.printStackTrace();
93          } catch (CredentialNotFoundException e) {
94  	        // TODO Auto-generated catch block
95  	        e.printStackTrace();
96          }
97  		settings = new GroupModel("GWE Settings", "Slicer3 GWE Settings");
98  
99  		List<String> clustersNamesList = new ArrayList<String>();
100 		for (HeadResourceInfo daemonInfo : appConfig.getGrid().getHeadResources()) clustersNamesList.add(daemonInfo.getName());
101 		String[] clustersNames = clustersNamesList.toArray(new String[]{});
102 		
103 		optClusterDesc = settings.addParam(new PMEnumString("Cluster", "gweCluster", "Name of the cluster descriptor to use to contact GWE daemon", null, clustersNames));
104 		optVariables   = settings.addParam(new PMString("Iteration Variables", "gweIterationVariables", "Variables to iterate to generate the commands to run in the cluster"));
105 		
106 		template = new OptionableAppTemplate(optClusterDesc, optVariables);
107 	}
108 
109 	public String getIterVariables() { return template.getArg(optVariables).replace(";", " "); }
110 	
111 	private HeadResourceInfo getClusterSelected() {
112 	    return appConfig.getGrid().getHeadResource(template.getArg(optClusterDesc));
113     }
114 	
115 	public String generateProxyXML() {
116 		String gweGroup = VelocityUtils.merge("group", settings, IOUtils.readClassPathFile("standardGroupModel.vm"));
117 		String proxyXML = proxiedModule.generateProxyXML().replaceFirst("<parameters>", gweGroup + "<parameters>");
118 		proxyXML = proxyXML.replaceAll("image>", "string>");
119 		proxyXML = proxyXML.replaceAll("<image ", "<string ");
120 		proxyXML = proxyXML.replaceAll("directory>", "string>");
121 		proxyXML = proxyXML.replaceAll("file>", "string>");
122 		proxyXML = proxyXML.replaceAll("integer>", "string>");
123 		proxyXML = proxyXML.replaceAll("float>", "string>");
124 		proxyXML = proxyXML.replaceAll("double>", "string>");
125 		proxyXML = proxyXML.replaceFirst("</title>", " - GWE Powered</title>");
126 		proxyXML = proxyXML.replaceFirst("</description>", "\n\nPowered by GWE</description>");
127 		return proxyXML;
128 	}
129 
130 	public String runProxyApp(String[] args) throws P2ELSyntaxException {
131 		template.loadArgs(args);
132 		
133 		// Read daemon info from configuration associated with the cluster selected in Slicer UI 
134 		HeadResourceInfo daemonInfo = getClusterSelected();
135         
136         // Create P2EL command
137 		String moduleInvocation = proxiedModule.getModuleInvocation(VAR_SLICER_HOME);
138 		String moduleArgs = StringUtils.getArrayAsStr(template.getWithoutOptionsArgs(args));
139 		String stmt = generateP2ELStatement(getIterVariables(), moduleInvocation, moduleArgs);
140 		
141 		try {
142             queueOrder(stmt, null);
143         } catch (Exception e) {
144         	progressTracker.trackProgress(getExceptionMessage(e));
145 			log.error(e);
146 			System.exit(1);
147         }
148         return "";
149 	}
150 
151 	public String generateP2ELStatement(String p2elVars, String moduleInvocation, String moduleArgs) {
152 		String[] functionNames = GWEAppContext.getP2ELFunctionNames().toArray(new String[]{});
153 		String[] regexps = new String[]{"\\$(" + REXUtils.options(functionNames) + ")\\(([^\\(\\),]*[,]?){1,}\\)"};
154 		
155 		int varCount = 1;
156 		List<List<String>> matches = REXUtils.findRepeatsStrong(moduleArgs, regexps, true);
157 		for (List<String> parts : matches) {
158 	        String varRef = "${VAR_" + varCount++ + "}";
159 	        String functionInvocation = parts.get(0);
160 	        int startIndex = moduleArgs.indexOf(functionInvocation);
161 	        int endIndex = startIndex + functionInvocation.length();
162 	        moduleArgs = moduleArgs.substring(0, startIndex) + varRef + moduleArgs.substring(endIndex); 
163 			p2elVars += " " + varRef + "=" + functionInvocation;
164         }
165 		
166 		return p2elVars + " " + moduleInvocation + " " + moduleArgs;
167 	}
168 
169 	public void queueOrder(String stmt, String email) throws ServerAPIConnectionException, PasswordMismatchException, RemoteException, P2ELSyntaxException, InstallerException {
170 		Session4ClientAPIEnhancer session = appConfig.getSessionsRepository().getSession(getClusterSelected(), true);
171 
172 		// Create monitoring listener
173 		GWECLMProxyAppEventListener listener = monitorDaemonEvents();
174 		
175 		// Queue Order
176 		OrderInfo order = new OrderInfo(new POrderDescriptor<String>(stmt), email);
177 		order.setResultParserClass(SlicerResultParser.class);
178 		try {
179 			progressTracker.trackProgress("Queueing order...");
180 			int orderId = session.queueOrder(order).getId();
181 			progressTracker.trackProgress("Order '" + orderId + "' queued!");
182 			// Report progress for order just queued
183 			// TODO: Replace with commands count read from daemon after it expanded the order
184 			if (listener != null) 
185 				listener.reportProgressFor(orderId);
186 		} catch (GWEDomainException e) {
187 			// IMPOSSIBLE! Abstract exception super class of all GWE level exceptions. The specific subclasses generated will be thrown
188 		}
189 	}
190 	
191 	private String getExceptionMessage(Exception e) {
192 		if (e instanceof ServerAPIConnectionException) return "Unable to connect to the GWE daemon"; 
193 		if (e instanceof PasswordMismatchException)    return "GWE password mismatch error"; 
194 		if (e instanceof P2ELSyntaxException)          return "P2EL syntax error";
195 		if (e instanceof RemoteException)              return "Daemon reported error '" + e.getMessage() + "'";
196 		return "Error: " + e.getMessage();
197 	}
198 
199 	private GWECLMProxyAppEventListener monitorDaemonEvents() {
200 		try {
201 			GWECLMProxyAppEventListener evListener = new GWECLMProxyAppEventListener();
202 			appConfig.createDaemonConfig(getClusterSelected()).createAPILink().createEventMonitor().monitorEvents(evListener, new DefaultEventFilter(null));
203 			return evListener;
204 		} catch (Exception e) {
205 			// FIXME: Try to recover gracefully from an error that will prevent to report execution progress
206 		}
207 		return null;
208 	}
209 }