package net.enilink.komma.edit.provider; import java.util.Arrays; import java.util.regex.Pattern; import net.enilink.commons.iterator.IExtendedIterator; import net.enilink.commons.iterator.WrappedIterator; import net.enilink.komma.core.IDialect; import net.enilink.komma.core.IEntity; import net.enilink.komma.core.IEntityManager; import net.enilink.komma.core.IQuery; import net.enilink.komma.core.QueryFragment; import net.enilink.komma.core.URI; import net.enilink.komma.em.util.ISparqlConstants; public class SparqlSearchableItemProvider implements ISearchableItemProvider { private static Pattern ESCAPE_CHARS = Pattern.compile("[\\[.{(*+?^$|]"); protected IEntityManager getEntityManager(Object parent) { if (parent instanceof IEntity) { return ((IEntity) parent).getEntityManager(); } return null; } protected String getQueryFindPatterns(Object parent) { return "?parent komma:child* ?s . "; } protected void setQueryParameters(IQuery<?> query, Object parent) { if (parent != null) { query.setParameter("parent", parent); } } protected String patternToRegex(String pattern) { pattern = ESCAPE_CHARS.matcher(pattern).replaceAll("\\\\$0"); return pattern.replace("\\*", ".*").replace("\\?", "."); } @Override public IExtendedIterator<?> find(Object expression, Object parent, int limit) { IEntityManager em = getEntityManager(parent); if (expression instanceof String && em != null) { String findPatterns = getQueryFindPatterns(parent); String pattern = (String) expression; String uriPattern = pattern; if (!pattern.matches(".*[#/].*")) { int colonIndex = pattern.lastIndexOf(':'); if (colonIndex == 0) { pattern = pattern.substring(1); } uriPattern = "[#/:]" + patternToRegex(pattern) + "[^#/]*$"; if (colonIndex > 0) { String prefix = pattern.substring(0, colonIndex); pattern = pattern.substring(colonIndex + 1); URI namespaceUri = em.getNamespace(prefix); if (namespaceUri != null) { uriPattern = patternToRegex(namespaceUri .appendFragment("") + pattern); } } } IDialect dialect = em.getFactory().getDialect(); QueryFragment searchS = dialect.fullTextSearch(Arrays.asList("s"), IDialect.ALL, pattern); QueryFragment searchL = dialect.fullTextSearch(Arrays.asList("l"), IDialect.DEFAULT, pattern); boolean isFilter = Pattern .compile("^\\s*filter", Pattern.CASE_INSENSITIVE) .matcher(searchS.toString()).find(); String queryStr = ISparqlConstants.PREFIX + "SELECT DISTINCT ?s WHERE {" // // if FTS is implemented with regex filter then // add patterns first + (isFilter ? findPatterns : "") // + "{" // + " ?s rdfs:label ?l . " + searchL // + " FILTER regex(str(?l), ?labelPattern, \"i\")" // + "} UNION {" // + (isFilter ? " ?s ?p ?o . " : "") + searchS + " FILTER regex(str(?s), ?uriPattern, \"i\")" // + "} " // // if FTS is natively implemented then add // patterns last + (isFilter ? "" : findPatterns) // + "}"; if (limit > 0) { queryStr += " LIMIT " + limit; } IQuery<?> query = em.createQuery(queryStr); searchS.addParameters(query); searchL.addParameters(query); query.setParameter("uriPattern", uriPattern); query.setParameter("labelPattern", patternToRegex(pattern)); setQueryParameters(query, parent); return query.evaluate(); } return WrappedIterator.emptyIterator(); } }