1 19 20 package org.netbeans.modules.web.core.syntax.completion; 21 22 import java.io.IOException ; 23 import java.util.ArrayList ; 24 import java.util.Collections ; 25 import java.util.List ; 26 import java.util.logging.Level ; 27 import java.util.logging.Logger ; 28 import javax.lang.model.element.ExecutableElement; 29 import javax.lang.model.element.Modifier; 30 import javax.lang.model.element.TypeElement; 31 import javax.lang.model.type.TypeKind; 32 import javax.lang.model.type.TypeMirror; 33 import javax.lang.model.util.ElementFilter; 34 import org.netbeans.api.java.source.CancellableTask; 35 import org.netbeans.api.java.source.ClasspathInfo; 36 import org.netbeans.api.java.source.CompilationController; 37 import org.netbeans.api.java.source.CompilationInfo; 38 import org.netbeans.api.java.source.JavaSource; 39 import org.netbeans.api.java.source.JavaSource.Phase; 40 import org.netbeans.api.java.source.UiUtils; 41 import org.netbeans.api.jsp.lexer.JspTokenId; 42 import org.netbeans.api.lexer.Token; 43 import org.netbeans.api.lexer.TokenHierarchy; 44 import org.netbeans.api.lexer.TokenSequence; 45 import org.netbeans.editor.BaseDocument; 46 import org.netbeans.modules.el.lexer.api.ELTokenId; 47 import org.netbeans.modules.web.core.syntax.JspSyntaxSupport; 48 import org.netbeans.modules.web.jsps.parserapi.PageInfo.BeanData; 49 import org.netbeans.spi.editor.completion.CompletionItem; 50 51 57 58 59 63 public class ELExpression { 64 private static final Logger logger = Logger.getLogger(ELExpression.class.getName()); 65 66 67 public static final int NOT_EL = 0; 68 69 public static final int EL_START = 1; 70 71 public static final int EL_BEAN = 2; 72 73 public static final int EL_IMPLICIT =3; 74 75 public static final int EL_FUNCTION = 4; 76 77 public static final int EL_UNKNOWN = 5; 78 79 80 private String expression; 81 82 protected JspSyntaxSupport sup; 83 private String replace; 84 private boolean isDefferedExecution = false; 85 86 public ELExpression(JspSyntaxSupport sup) { 87 this.sup = sup; 88 this.replace = ""; 89 } 90 91 96 public int parse(int offset){ 97 String value = null; 98 int result = NOT_EL; 99 boolean middle; 100 101 BaseDocument document = sup.getDocument(); 102 document.readLock(); 103 try { 104 TokenHierarchy hi = TokenHierarchy.get(document); 105 TokenSequence ts = JspSyntaxSupport.tokenSequence(hi, ELTokenId.language(), offset); 106 if(ts == null) { 107 return EL_UNKNOWN; 109 } 110 111 TokenSequence jspTokenSequence = hi.tokenSequence(); 112 jspTokenSequence.move(offset); 113 if(!jspTokenSequence.moveNext()) { 114 return NOT_EL; } 116 117 Token jspToken = jspTokenSequence.token(); 118 isDefferedExecution = jspToken.text().toString().startsWith("#{"); 120 if (jspToken.id() == JspTokenId.EL){ 121 if (offset == jspToken.offset(hi) + "${".length()){ return EL_START; 123 } 124 } 125 126 ts.move(offset); 127 if (!ts.moveNext() && !ts.movePrevious()) { 128 return NOT_EL; 129 } 130 131 if (ts.offset() == offset){ 132 ts.movePrevious(); 133 } 134 135 Token<ELTokenId> token = ts.token(); 138 while (token.id() != ELTokenId.LPAREN 139 && token.id() != ELTokenId.WHITESPACE 140 && (!token.id().language().nonPrimaryTokenCategories(token.id()).contains(ELTokenId.ELTokenCategories.KEYWORDS.name()) 141 || token.id().language().nonPrimaryTokenCategories(token.id()).contains(ELTokenId.ELTokenCategories.NUMERIC_LITERALS.name()))) { 142 token = ts.token(); 143 if (value == null){ 144 value = token.text().toString(); 145 if (token.id() == ELTokenId.DOT){ 146 replace=""; 147 middle = true; 148 } else if (token.text().length() >= (offset-token.offset(hi))){ 149 if (token.offset(hi) <= offset){ 150 value = value.substring(0, offset-token.offset(hi)); 151 replace = value; 152 } else { 153 return NOT_EL; 155 } 156 } 157 } else { 158 value = token.text().toString() + value; 159 if (token.id() == ELTokenId.TAG_LIB_PREFIX) 160 replace = value; 161 } 162 if(!ts.movePrevious()) { 163 break; } 165 } 166 if (token.id() != ELTokenId.IDENTIFIER && token.id() != ELTokenId.TAG_LIB_PREFIX ) { 167 value = null; 168 } else 169 if (token.id() == ELTokenId.WHITESPACE || token.id() == ELTokenId.LPAREN) { 170 result = EL_START; 171 } else 172 if (value != null){ 173 result = findContext(value); 174 } 175 } finally { 176 document.readUnlock(); 177 } 178 expression = value; 179 return result; 180 } 181 182 public List <CompletionItem> getPropertyCompletionItems(String beanType){ 183 PropertyCompletionItemsTask task = new PropertyCompletionItemsTask(beanType); 184 runTask(task); 185 186 return task.getCompletionItems(); 187 } 188 189 public boolean gotoPropertyDeclaration(String beanType){ 190 GoToSourceTask task = new GoToSourceTask(beanType); 191 runTask(task); 192 return task.wasSuccessful(); 193 } 194 195 198 public String getObjectClass(){ 199 String beanName = extractBeanName(); 200 201 BeanData[] allBeans = sup.getBeanData(); 202 for (BeanData beanData : allBeans) { 203 if (beanData.getId().equals(beanName)){ 204 return beanData.getClassName(); 205 } 206 } 207 208 ELImplicitObjects.ELImplicitObject implObj = ELImplicitObjects.getELImplicitObject(beanName); 210 211 if (implObj != null){ 212 return implObj.getClazz(); 213 } 214 215 return null; 216 } 217 218 private void runTask(CancellableTask task){ 219 ClasspathInfo cpInfo = ClasspathInfo.create(sup.getFileObject()); 220 JavaSource source = JavaSource.create(cpInfo, Collections.EMPTY_LIST); 221 222 try{ 223 source.runUserActionTask(task, true); 224 } catch (IOException e){ 225 logger.log(Level.SEVERE, e.getMessage(), e); 226 } 227 } 228 229 public String extractBeanName(){ 230 String elExp = getExpression(); 231 232 if (elExp != null && !elExp.equals("")){ 233 if (elExp.indexOf('.')> -1){ 234 String beanName = elExp.substring(0,elExp.indexOf('.')); 235 return beanName; 236 } 237 } 238 239 return null; 240 } 241 242 public boolean isDefferedExecution(){ 243 return isDefferedExecution; 244 } 245 246 private String getPropertyBeingTypedName(){ 247 String elExp = getExpression(); 248 int dotPos = elExp.lastIndexOf('.'); 249 250 return dotPos == -1 ? null : elExp.substring(dotPos + 1); 251 } 252 253 private abstract class BaseELTaskClass{ 254 protected String beanType; 255 256 BaseELTaskClass(String beanType){ 257 this.beanType = beanType; 258 } 259 260 263 protected TypeElement getTypePreceedingCaret(CompilationInfo parameter){ 264 if (beanType == null){ 265 return null; 266 } 267 268 TypeElement lastKnownType = parameter.getElements().getTypeElement(beanType); 269 270 String parts[] = getExpression().split("\\."); 271 274 int limit = parts.length - 1; 275 276 if (getPropertyBeingTypedName().length() == 0){ 277 limit += 1; 278 } 279 280 for (int i = 1; i < limit; i ++){ 281 if (lastKnownType == null){ 282 logger.fine("EL CC: Could not resolve type for property " + parts[i] + " in " + getExpression()); 285 return null; 286 } 287 288 String accessorName = getAccessorName(parts[i]); 289 List <ExecutableElement> allMethods = ElementFilter.methodsIn(lastKnownType.getEnclosedElements()); 290 lastKnownType = null; 291 292 for (ExecutableElement method : allMethods){ 293 if (accessorName.equals(method.getSimpleName().toString())){ 294 TypeMirror returnType = method.getReturnType(); 295 296 if (returnType.getKind() == TypeKind.DECLARED){ lastKnownType = (TypeElement) parameter.getTypes().asElement(returnType); 298 break; 299 } 300 } 301 302 } 303 } 304 305 return lastKnownType; 306 } 307 308 protected String getAccessorName(String propertyName){ 309 return "get" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); 311 } 312 313 316 protected String getExpressionSuffix(ExecutableElement method){ 317 318 if (method.getModifiers().contains(Modifier.PUBLIC) 319 && method.getParameters().size() == 0){ 320 String methodName = method.getSimpleName().toString(); 321 322 if (methodName.startsWith("get")){ return Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4); 324 } 325 326 if (methodName.startsWith("is")){ return Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3); 328 } 329 330 if (isDefferedExecution()){ 331 333 if ("java.lang.String".equals(method.getReturnType().toString())){ return methodName; 335 } 336 } 337 } 338 339 return null; } 341 342 public void cancel() {} 343 } 344 345 349 private class GoToSourceTask extends BaseELTaskClass implements CancellableTask<CompilationController>{ 350 private boolean success = false; 351 352 GoToSourceTask(String beanType){ 353 super(beanType); 354 } 355 356 public void run(CompilationController parameter) throws Exception { 357 parameter.toPhase(Phase.ELEMENTS_RESOLVED); 358 TypeElement bean = getTypePreceedingCaret(parameter); 359 360 if (bean != null){ 361 String suffix = getPropertyBeingTypedName(); 362 363 for (ExecutableElement method : ElementFilter.methodsIn(bean.getEnclosedElements())){ 364 String propertyName = getExpressionSuffix(method); 365 366 if (propertyName != null && propertyName.equals(suffix)){ 367 success = UiUtils.open(parameter.getClasspathInfo(), method); 368 break; 369 } 370 } 371 } 372 } 373 374 public boolean wasSuccessful(){ 375 return success; 376 } 377 } 378 379 private class PropertyCompletionItemsTask extends BaseELTaskClass implements CancellableTask<CompilationController>{ 380 381 private List <CompletionItem> completionItems = new ArrayList <CompletionItem>(); 382 383 PropertyCompletionItemsTask(String beanType){ 384 super(beanType); 385 } 386 387 public void run(CompilationController parameter) throws Exception { 388 parameter.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED); 389 390 TypeElement bean = getTypePreceedingCaret(parameter); 391 392 if (bean != null){ 393 String prefix = getPropertyBeingTypedName(); 394 395 for (ExecutableElement method : ElementFilter.methodsIn(bean.getEnclosedElements())){ 396 String propertyName = getExpressionSuffix(method); 397 398 if (propertyName != null && propertyName.startsWith(prefix)){ 399 boolean isMethod = propertyName.equals(method.getSimpleName().toString()); 400 String type = isMethod ? "" : method.getReturnType().toString(); 402 CompletionItem item = new JspCompletionItem.ELProperty( 403 propertyName, type); 404 405 completionItems.add(item); 406 } 407 } 408 } 409 } 410 411 public List <CompletionItem> getCompletionItems(){ 412 return completionItems; 413 } 414 } 415 416 419 protected int findContext(String expr){ 420 int dotIndex = expr.indexOf('.'); 421 int bracketIndex = expr.indexOf('['); 422 int value = EL_UNKNOWN; 423 424 if (bracketIndex == -1 && dotIndex > -1){ 425 String first = expr.substring(0, dotIndex); 426 BeanData[] beans = sup.getBeanData(); 427 if (beans != null) { 428 for (int i = 0; i < beans.length; i++) 429 if (beans[i].getId().equals(first)){ 430 value = EL_BEAN; 431 continue; 432 } 433 } 434 if (value == EL_UNKNOWN && ELImplicitObjects.getELImplicitObjects(first).size()>0) 435 value = EL_IMPLICIT; 436 } else if (bracketIndex == -1 && dotIndex == -1) 437 value = EL_START; 438 return value; 439 } 440 441 442 public String getExpression() { 443 return expression; 444 } 445 446 public void setExpression(String expression) { 447 this.expression = expression; 448 } 449 450 public String getReplace() { 451 return replace; 452 } 453 454 } 455 | Popular Tags |