blob: ef5dd112e96c03750c27170e5d45a7c8dfa2165b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.web.el;
import com.sun.el.parser.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ELException;
import org.netbeans.modules.parsing.api.Snapshot;
import org.netbeans.modules.parsing.spi.Parser.Result;
import org.netbeans.modules.parsing.spi.indexing.Context;
import org.netbeans.modules.parsing.spi.indexing.EmbeddingIndexer;
import org.netbeans.modules.parsing.spi.indexing.EmbeddingIndexerFactory;
import org.netbeans.modules.parsing.spi.indexing.Indexable;
import org.netbeans.modules.parsing.spi.indexing.support.IndexDocument;
import org.netbeans.modules.parsing.spi.indexing.support.IndexingSupport;
import org.netbeans.modules.web.el.spi.ELPlugin;
/**
* Expression Language indexer.
*
* TODO: should store node offsets to the index
*
* @author Erno Mononen
*/
public final class ELIndexer extends EmbeddingIndexer {
private static final Logger LOGGER = Logger.getLogger(ELIndexer.class.getName());
@Override
protected void index(Indexable indexable, Result parserResult, Context context) {
ELParserResult elResult = (ELParserResult) parserResult;
if (!elResult.hasElements()) {
return;
}
IndexingSupport support;
try {
support = IndexingSupport.getInstance(context);
} catch (IOException ioe) {
LOGGER.log(Level.WARNING, null, ioe);
return;
}
new Analyzer(elResult, support).analyze();
}
private static class Analyzer implements NodeVisitor {
private final ELParserResult parserResult;
private final IndexingSupport support;
private final List<IndexDocument> documents = new ArrayList<>();
public Analyzer(ELParserResult parserResult, IndexingSupport support) {
this.parserResult = parserResult;
this.support = support;
}
void analyze() {
for (final ELElement each : parserResult.getElements()) {
if (each.isValid()) {
IndexDocument doc = support.createDocument(parserResult.getFileObject());
documents.add(doc);
addPair(Fields.EXPRESSION, each.getExpression().getPreprocessedExpression());
each.getNode().accept(this);
support.addDocument(doc);
}
}
}
private IndexDocument getCurrent() {
assert !documents.isEmpty() : "No current document";
return documents.get(documents.size() - 1);
}
public List<IndexDocument> getDocuments() {
return documents;
}
private void addPair(String key, String value) {
if(value != null) {
getCurrent().addPair(key, value, true, true);
}
}
@Override
public void visit(Node node) throws ELException {
if (node instanceof AstIdentifier) {
String identifier = ((AstIdentifier) node).getImage();
addPair(Fields.IDENTIFIER, identifier);
} else if (NodeUtil.isMethodCall(node)) {
String method = node.getImage();
addPair(Fields.METHOD, method);
} else if (node instanceof AstDotSuffix) {
String property = ((AstDotSuffix) node).getImage();
addPair(Fields.PROPERTY, property);
}
}
}
public static final class Fields {
public static final String SEPARATOR = "|";
public static final String EXPRESSION = "expression";
public static final String IDENTIFIER = "identifier";
public static final String IDENTIFIER_FULL_EXPRESSION = "identifier_full_expression";
public static final String PROPERTY = "property";
public static final String PROPERTY_OWNER = "property_owner";
public static final String PROPERTY_FULL_EXPRESSION = "property_full_expression";
public static final String METHOD = "method";
public static final String METHOD_FULL_EXPRESSION = "method_full_expression";
static String encode(String... values) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < values.length; i++) {
result.append(values[i]);
if (i + 1 < values.length) {
result.append(SEPARATOR);
}
}
return result.toString();
}
public static String[] split(String field) {
return field.split("\\" + SEPARATOR);
}
}
public static final class Factory extends EmbeddingIndexerFactory {
static final String NAME = "EL"; //NOI18N
static final int VERSION = 1;
private static Collection<String> INDEXABLE_MIMETYPES;
private static synchronized Collection<String> getIndexableMimeTypes() {
if(INDEXABLE_MIMETYPES == null) {
INDEXABLE_MIMETYPES = new ArrayList<>();
for(ELPlugin plugin : ELPlugin.Query.getELPlugins()) {
INDEXABLE_MIMETYPES.addAll(plugin.getMimeTypes());
}
}
return INDEXABLE_MIMETYPES;
}
@Override
public EmbeddingIndexer createIndexer(Indexable indexable, Snapshot snapshot) {
if (isIndexable(indexable, snapshot)) {
return new ELIndexer();
}
return null;
}
private static boolean isIndexable(Indexable indexable, Snapshot snapshot) {
return getIndexableMimeTypes().contains(indexable.getMimeType());
}
@Override
public void filesDeleted(Iterable<? extends Indexable> deleted, Context context) {
}
@Override
public void filesDirty(Iterable<? extends Indexable> dirty, Context context) {
}
@Override
public String getIndexerName() {
return NAME;
}
@Override
public int getIndexVersion() {
return VERSION;
}
}
}