View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
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  package org.argeo.slc.client.ui.editors;
17  
18  import java.text.DateFormat;
19  import java.text.SimpleDateFormat;
20  import java.util.List;
21  import java.util.SortedMap;
22  import java.util.TreeMap;
23  
24  import javax.jcr.Node;
25  import javax.jcr.NodeIterator;
26  import javax.jcr.RepositoryException;
27  import javax.jcr.Workspace;
28  import javax.jcr.observation.Event;
29  import javax.jcr.observation.EventListener;
30  import javax.jcr.query.Query;
31  
32  import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
33  import org.argeo.slc.SlcException;
34  import org.argeo.slc.SlcNames;
35  import org.argeo.slc.SlcTypes;
36  import org.argeo.slc.execution.ExecutionStep;
37  import org.eclipse.swt.SWT;
38  import org.eclipse.swt.widgets.Composite;
39  import org.eclipse.swt.widgets.Control;
40  import org.eclipse.swt.widgets.Display;
41  import org.eclipse.swt.widgets.Text;
42  import org.eclipse.ui.forms.editor.FormEditor;
43  import org.eclipse.ui.forms.editor.FormPage;
44  import org.eclipse.ui.forms.widgets.FormToolkit;
45  
46  public class ProcessLogPage extends FormPage {
47  	public final static String ID = "processLogPage";
48  
49  	private DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
50  
51  	/** Where the log is displayed. */
52  	private Text text;
53  	/**
54  	 * Stores logs received before the text was shown. TODO : rather store in in
55  	 * JCR and reads it from there.
56  	 */
57  	private StringBuffer beforeTextInit = new StringBuffer("");
58  
59  	private Node processNode;
60  	/**
61  	 * optimization field: we compute once the length of the path to slc:log so
62  	 * that we can easily substring the relative path of logs.
63  	 */
64  	//private Integer logPathLength;
65  
66  	public ProcessLogPage(FormEditor editor, Node processNode) {
67  		super(editor, ID, "Log");
68  		this.processNode = processNode;
69  
70  		EventListener listener = new LogListener(editor.getSite().getPage()
71  				.getWorkbenchWindow().getWorkbench().getDisplay());
72  
73  		try {
74  			String logBasePath = processNode.getPath() + '/' + SlcNames.SLC_LOG;
75  			//logPathLength = logBasePath.length();
76  
77  			Workspace ws = processNode.getSession().getWorkspace();
78  
79  			String statement = "SELECT * FROM ["
80  					+ SlcTypes.SLC_LOG_ENTRY
81  					+ "] as logEntry"
82  					+ " WHERE ISDESCENDANTNODE('"
83  					+ logBasePath
84  					+ "')"
85  					+ " ORDER BY logEntry.[slc:timestamp] ASC, NAME(logEntry) ASC";
86  			StringBuffer buf = new StringBuffer("");
87  			NodeIterator it = ws.getQueryManager()
88  					.createQuery(statement, Query.JCR_SQL2).execute()
89  					.getNodes();
90  			while (it.hasNext())
91  				appendLogEntry(buf, it.nextNode());
92  			beforeTextInit = new StringBuffer(buf.toString());
93  			// text.setText(buf.toString());
94  			ws.getObservationManager().addEventListener(listener,
95  					Event.NODE_ADDED, logBasePath, true, null, null, false);
96  		} catch (RepositoryException e) {
97  			throw new SlcException("Cannot register listener", e);
98  		}
99  	}
100 
101 	@Override
102 	public synchronized void createPartControl(Composite parent) {
103 		// bypass createFormContent
104 		FormToolkit tk = getEditor().getToolkit();
105 		// parent.setLayout(new FillLayout());
106 		text = tk.createText(parent, "", SWT.MULTI | SWT.H_SCROLL
107 				| SWT.V_SCROLL);
108 		text.setEditable(false);
109 
110 		// transfer the existing buffer the first time
111 		if (beforeTextInit.length() > 0) {
112 			text.append(beforeTextInit.toString());
113 			// clear buffer
114 			beforeTextInit.setLength(0);
115 		}
116 
117 	}
118 
119 	// @Override
120 	// protected synchronized void createFormContent(IManagedForm mf) {
121 	// ScrolledForm form = mf.getForm();
122 	// form.setExpandHorizontal(true);
123 	// form.setExpandVertical(true);
124 	// // form.setText("Log");
125 	// FillLayout mainLayout = new FillLayout();
126 	// form.getBody().setLayout(mainLayout);
127 	//
128 	// FormToolkit tk = getManagedForm().getToolkit();
129 	// text = tk.createText(form.getBody(), "", SWT.MULTI | SWT.H_SCROLL
130 	// | SWT.V_SCROLL);
131 	// text.setEditable(false);
132 	// // transfer the existing buffer the first time
133 	// if (beforeTextInit.length() > 0) {
134 	// text.append(beforeTextInit.toString());
135 	// // clear buffer
136 	// beforeTextInit.setLength(0);
137 	// }
138 	// }
139 
140 	protected void appendLogEntry(StringBuffer buf, Node logEntry)
141 			throws RepositoryException {
142 		// +1 in order to remove the first slash
143 //		String relPath = logEntry.getPath().substring(logPathLength + 1);
144 		//System.out.println("relPath=" + relPath);
145 //		int firstSlashIndex = relPath.indexOf('/');
146 //		int lastSlashIndex = relPath.lastIndexOf('/');
147 //		String thread = relPath.substring(0, firstSlashIndex);
148 //		String location = relPath.substring(firstSlashIndex, lastSlashIndex);
149 
150 		// String date = dateFormat.format(logEntry
151 		// .getProperty(SlcNames.SLC_TIMESTAMP).getDate().getTime());
152 		String date = logEntry.getProperty(SlcNames.SLC_TIMESTAMP).getString();
153 		buf.append(date).append(' ');
154 		String type = logEntry.getPrimaryNodeType().getName().substring(7);
155 		buf.append(type).append('\t');
156 		// buf.append(thread).append('\t');
157 		// buf.append(location).append('\t');
158 		buf.append(logEntry.getProperty(SlcNames.SLC_MESSAGE).getString());
159 		buf.append('\n');
160 
161 	}
162 
163 	/** @deprecated */
164 	public synchronized void addSteps(List<ExecutionStep> steps) {
165 		final StringBuffer buf = new StringBuffer("");
166 		for (ExecutionStep step : steps) {
167 			buf.append(dateFormat.format(step.getTimestamp()));
168 			buf.append(' ');
169 			if (step.getType().equals(ExecutionStep.PHASE_START)) {
170 				buf.append("## START ").append(step.getLog());
171 				buf.append('\n');
172 			} else if (step.getType().equals(ExecutionStep.PHASE_END)) {
173 				buf.append("## END   ").append(step.getLog());
174 				buf.append("\n");
175 			} else {
176 				buf.append(step.getLog());
177 			}
178 		}
179 
180 		if (text != null) {
181 			Display.getDefault().asyncExec(new Runnable() {
182 				public void run() {
183 					text.append(buf.toString());
184 				}
185 			});
186 		} else
187 			beforeTextInit.append(buf);
188 	}
189 
190 	@Override
191 	public Control getPartControl() {
192 		return text;
193 	}
194 
195 	@Override
196 	public void setFocus() {
197 		if (text != null)
198 			text.setFocus();
199 	}
200 
201 	/** JCR event listener notifying when new nodes are added */
202 	private class LogListener extends AsyncUiEventListener {
203 
204 		public LogListener(Display display) {
205 			super(display);
206 		}
207 
208 		@Override
209 		protected void onEventInUiThread(List<Event> events)
210 				throws RepositoryException {
211 			// since we use batch save, order is not guaranteed
212 			// so we need to reorder, according to log line number for the time
213 			// being
214 			SortedMap<Long, Node> nodes = new TreeMap<Long, Node>();
215 
216 			for (Event evt : events) {
217 				Node newNode = ProcessLogPage.this.processNode.getSession()
218 						.getNode(evt.getPath());
219 				if (newNode.isNodeType(SlcTypes.SLC_LOG_ENTRY)) {
220 					nodes.put(Long.parseLong(newNode.getName()), newNode);
221 				}
222 			}
223 
224 			StringBuffer buf = new StringBuffer("");
225 			for (Node logEntry : nodes.values()) {
226 				appendLogEntry(buf, logEntry);
227 			}
228 
229 			if (text != null)
230 				text.append(buf.toString());
231 			else
232 				beforeTextInit.append(buf);
233 		}
234 	}
235 }