1 /* ====================================================================
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 2000 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
53 *
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
57 */
58 package com.bonevich.eclipse.logging.popups;
59
60 import com.bonevich.eclipse.logging.LoggingPlugin;
61 import com.bonevich.eclipse.logging.LoggingPluginMessages;
62 import com.bonevich.eclipse.logging.LoggingPluginResources;
63
64 import org.apache.commons.logging.Log;
65 import org.apache.commons.logging.LogFactory;
66 import org.eclipse.core.resources.IProject;
67 import org.eclipse.core.runtime.*;
68 import org.eclipse.jdt.core.*;
69 import org.eclipse.jface.text.*;
70 import org.eclipse.jface.text.IRegion;
71 import org.eclipse.ui.IFileEditorInput;
72 import org.eclipse.ui.actions.WorkspaceModifyOperation;
73 import org.eclipse.ui.texteditor.ITextEditor;
74
75 import java.lang.reflect.InvocationTargetException;
76 import java.util.StringTokenizer;
77
78 /***
79 * Workhorse for adding logging statements to a given source code editor.
80 *
81 * @author jbonevic
82 */
83 public class AddLoggingOperation
84 extends WorkspaceModifyOperation
85 implements LoggingPluginResources
86 {
87 private static final Log _logger = LogFactory.getLog(AddLoggingOperation.class);
88
89 private static final String DUPLICATE = "duplicate entry";
90 private static final String EXISTS = "already exists";
91
92 private ITextEditor _editor;
93 private ICompilationUnit _unit;
94 private AddLoggingAction _action;
95 private boolean _saveWork = true;
96
97 public AddLoggingOperation(
98 ITextEditor editor,
99 ICompilationUnit cu,
100 AddLoggingAction action,
101 boolean saveWork)
102 {
103 super();
104 _editor = editor;
105 _unit = cu;
106 _action = action;
107 _saveWork = saveWork;
108 }
109
110 /***
111 * @see WorkspaceModifyOperation#execute(IProgressMonitor)
112 */
113 protected void execute(IProgressMonitor monitor)
114 throws CoreException, InvocationTargetException, InterruptedException
115 {
116 if (monitor == null)
117 {
118 monitor = new NullProgressMonitor();
119 }
120 monitor.beginTask(LoggingPluginMessages.bind(ADD_LOGGING_DIALOG), 3);
121
122 IDocument document = _editor.getDocumentProvider().getDocument(_editor.getEditorInput());
123 String lineDelimiter = getLineDelimiter(document);
124 int tabWidth = getTabWidth();
125 String loggingImpl = LoggingPlugin.getPlugin().getLoggingImplementationPreference();
126
127 linkLoggerLibrary(loggingImpl, monitor);
128 monitor.worked(1);
129
130 addLoggerImports(loggingImpl);
131 monitor.worked(1);
132
133 addLoggerField(loggingImpl, lineDelimiter, tabWidth);
134 monitor.worked(1);
135
136 addLoggingStatement(loggingImpl, document, lineDelimiter, tabWidth);
137 monitor.done();
138 }
139
140 private void linkLoggerLibrary(String loggingImpl, IProgressMonitor monitor)
141 {
142 if (! LoggingPlugin.LOGGING_PREFS_API_JDK_1_4.equals(loggingImpl))
143 {
144 String name = LoggingPluginMessages.bind(LOGGING_LIB_PATHVAR + loggingImpl);
145 IClasspathEntry variableEntry = JavaCore.newVariableEntry(new Path(name), null, null, true);
146
147 IFileEditorInput input = (IFileEditorInput) _editor.getEditorInput();
148 IProject project = input.getFile().getProject();
149 IJavaProject javaProject = JavaCore.create(project);
150 try
151 {
152 IClasspathEntry[] classpathEntries = javaProject.getRawClasspath();
153 IClasspathEntry[] newEntries = new IClasspathEntry[classpathEntries.length + 1];
154 System.arraycopy(classpathEntries, 0 , newEntries, 0, classpathEntries.length);
155 newEntries[newEntries.length - 1] = variableEntry;
156 javaProject.setRawClasspath(newEntries, monitor);
157 }
158 catch (JavaModelException e)
159 {
160 if (e.getMessage().indexOf(DUPLICATE) < 0)
161 {
162 _logger.error("Error adding library", e);
163 }
164 }
165
166 }
167 }
168
169 private void addLoggerImports(String loggingImpl) throws JavaModelException
170 {
171 String imports = LoggingPluginMessages.bind(LOGGING_IMPORT_CLASS + loggingImpl);
172 StringTokenizer tokenizer = new StringTokenizer(imports, " ,");
173 while (tokenizer.hasMoreTokens())
174 {
175 _unit.createImport(tokenizer.nextToken(), null, null);
176 }
177 }
178
179 private void addLoggerField(String loggingImpl, String lineDelimiter, int tabWidth) throws JavaModelException
180 {
181 IType[] types = _unit.getTypes();
182 if (types.length > 0)
183 {
184 IType type = types[0];
185 int indentLevel = getIndentationLevel(type, tabWidth) + 1;
186
187 String field = LoggingPluginMessages.bind(
188 LOGGING_FIELD_DECLARATION + loggingImpl,
189 LoggingPlugin.getPlugin().getFieldNamePreference(),
190 type.getElementName()
191 );
192
193 String formattedField = formatStatement(field + lineDelimiter, lineDelimiter, indentLevel);
194
195 try
196 {
197 type.createField(formattedField, null, false, null);
198 }
199 catch (JavaModelException e)
200 {
201 // name collisions should be ignored - if a field already exists, do not fail
202 if (e.getMessage().indexOf(EXISTS) < 0)
203 {
204 _logger.error("Failed to add field", e);
205 }
206 }
207 }
208 }
209
210 private void addLoggingStatement(String loggingImpl, IDocument document, String lineDelimiter, int tabWidth)
211 {
212 try
213 {
214 ITextSelection selection = (ITextSelection) _editor.getSelectionProvider().getSelection();
215 int offset = selection.getOffset();
216 IRegion lineInfo = document.getLineInformationOfOffset(offset);
217 int lineOffset = lineInfo.getOffset();
218 int lineLength = lineInfo.getLength();
219 int indentLevel = getIndentationLevel(document.get(lineOffset, lineLength), tabWidth);
220 int eolOffset = lineOffset + lineLength;
221 document.replace(eolOffset, 0, lineDelimiter);
222
223 String statement = null;
224 if (_action.isConditionalUsed())
225 {
226 statement = _action.getConditionalLoggingStatement(loggingImpl);
227 }
228 else
229 {
230 statement = _action.getLoggingStatement(loggingImpl);
231 }
232
233 String formatterStatement = formatStatement(statement, lineDelimiter, indentLevel);
234
235 // append the formatted logging statement to this line
236 document.replace(eolOffset + lineDelimiter.length(), 0, formatterStatement);
237 }
238 catch (BadLocationException ignore)
239 {
240 }
241 }
242
243 private String formatStatement(String statement, String lineDelimiter, int indentLevel)
244 {
245 ICodeFormatter formatter = ToolFactory.createDefaultCodeFormatter(null);
246 return formatter.format(statement, indentLevel, null, lineDelimiter);
247 }
248
249 private String getLineDelimiter(IDocument document)
250 {
251 String delim = null;
252 try
253 {
254 delim = document.getLineDelimiter(0);
255 }
256 catch (BadLocationException e)
257 {
258 String[] delims = document.getLegalLineDelimiters();
259 if (delims.length > 0)
260 {
261 delim = delims[0];
262 }
263 if (delim == null)
264 {
265 delim = System.getProperty("line.separator", "\n");
266 }
267 }
268 return delim;
269 }
270
271 private int getIndentationLevel(IType type, int tabWidth)
272 {
273 try
274 {
275 IBuffer buf = _unit.getBuffer();
276 int offset = type.getSourceRange().getOffset();
277 int count = 0;
278 int blanks = 0;
279 while (offset > 0)
280 {
281 char ch = buf.getChar(offset--);
282 switch (ch)
283 {
284 case '\t' :
285 ++count;
286 blanks = 0;
287 break;
288 case ' ' :
289 if (++blanks == tabWidth)
290 {
291 ++count;
292 blanks = 0;
293 }
294 break;
295 default :
296 return count;
297 }
298 }
299 return count;
300 }
301 catch (JavaModelException e)
302 {
303 return 0;
304 }
305 }
306
307 private int getIndentationLevel(String line, int tabWidth)
308 {
309 int count = 0;
310 int blanks = 0;
311 int length = line.length();
312 for (int i = 0; i < length; i++)
313 {
314 char ch = line.charAt(i);
315 switch (ch)
316 {
317 case '\t' :
318 ++count;
319 blanks = 0;
320 break;
321 case ' ' :
322 if (++blanks == tabWidth)
323 {
324 ++count;
325 blanks = 0;
326 }
327 break;
328 default :
329 return count;
330 }
331 }
332 return count;
333 }
334
335 private int getTabWidth()
336 {
337 return Integer.parseInt(JavaCore.getOption(JavaCore.FORMATTER_TAB_SIZE));
338 }
339 }
This page was automatically generated by Maven