X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=bundles%2Forg.simantics.modeling%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fservices%2FCaseInsensitiveComponentFunctionNamingStrategy.java;h=feef9c8992fce52eec3e4417e45897762bf06b03;hb=1dfeb7d5c49b1391cd9d877e1eddab18995cb151;hp=75f1108f00e8f5457cd8815b6c969cd43c8adeac;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/services/CaseInsensitiveComponentFunctionNamingStrategy.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/services/CaseInsensitiveComponentFunctionNamingStrategy.java index 75f1108f0..feef9c899 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/services/CaseInsensitiveComponentFunctionNamingStrategy.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/services/CaseInsensitiveComponentFunctionNamingStrategy.java @@ -1,337 +1,339 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.modeling.services; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Formatter; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; - -import org.simantics.databoard.Bindings; -import org.simantics.db.ReadGraph; -import org.simantics.db.Resource; -import org.simantics.db.common.Indexing; -import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; -import org.simantics.db.common.request.PossibleIndexRoot; -import org.simantics.db.common.request.UnaryRead; -import org.simantics.db.common.utils.NameUtils; -import org.simantics.db.exception.DatabaseException; -import org.simantics.db.layer0.genericrelation.IndexQueries; -import org.simantics.db.service.GraphChangeListenerSupport; -import org.simantics.layer0.Layer0; -import org.simantics.scl.runtime.function.Function; -import org.simantics.scl.runtime.function.Function1; -import org.simantics.scl.runtime.tuple.Tuple3; -import org.simantics.scl.runtime.tuple.Tuple4; -import org.simantics.structural.stubs.StructuralResource2; - -import gnu.trove.set.hash.THashSet; - -/** - * A component naming strategy implementation for structural models based on an - * SCL function that lists used names in a model. - * - *

- * The type of the function is expected to be: - * ReadGraph => Resource -> String -> Integer -> List<Map<String,Object>> - * - * @author Tuukka Lehtonen - * - * @see ComponentNamingStrategy - */ -public class CaseInsensitiveComponentFunctionNamingStrategy extends ComponentNamingStrategyBase { - - protected static final boolean DEBUG_INDEX_SEARCH = false | DEBUG_ALL; - - @SuppressWarnings("rawtypes") - private final Function index; - - /** - * A filter that is applied to all user-provided name propositions before - * processing them. - */ - private Function1 propositionPreFilter; - - /** - * Construct an index-based naming strategy with "%s %d" as the generated - * name format. See {@link Formatter} for the format specification. - * - * @param index the index function for looking up used names. The function - * must be of type - * ReadGraph => Resource -> String -> Integer -> List<Map<String,Object>> - */ - @SuppressWarnings("rawtypes") - public CaseInsensitiveComponentFunctionNamingStrategy(Function index) { - this("%s %d", index); - } - - /** - * Construct an index-based naming strategy with the specified format as the - * generated name format. See {@link Formatter} for the format - * specification. - * - * @param generatedNameFormat the format to use for generated names, see - * {@link Formatter} - * @param index the index function for looking up used names. The function - * must be of type - * ReadGraph => Resource -> String -> Integer -> List<Map<String,Object>> - */ - @SuppressWarnings("rawtypes") - public CaseInsensitiveComponentFunctionNamingStrategy(String generatedNameFormat, Function index) { - super(generatedNameFormat); - this.index = index; - } - - /** - * Construct an index-based naming strategy with the specified format as the - * generated name format. See {@link Formatter} for the format - * specification. - * - * @param generatedNameFormat the format to use for generated names, see - * {@link Formatter} - * @param index the index function for looking up used names. The function - * must be of type - * ReadGraph => Resource -> String -> Integer -> List<Map<String,Object>> - * @param an optional function to - */ - @SuppressWarnings("rawtypes") - public CaseInsensitiveComponentFunctionNamingStrategy(String generatedNameFormat, Function index, Function1 propositionPreFilter) { - super(generatedNameFormat); - this.index = index; - this.propositionPreFilter = propositionPreFilter; - } - - CaseInsensitiveComponentNamingStrategy2 fallbackStrategy = null; - - @Override - public String validateInstanceName(ReadGraph graph, - Resource configurationRoot, Resource component, String proposition, boolean acceptProposition) - throws NamingException, DatabaseException { - - String lowercaseProposition = proposition.toLowerCase(); - - Layer0 L0 = Layer0.getInstance(graph); - String name = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING); - if (name != null) { - - String lowercaseName = name.toLowerCase(); - if(lowercaseName.startsWith(lowercaseProposition)) { - - Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(configurationRoot)); - if (indexRoot != null) { - - synchronized (this) { - - String search = "Name:" + lowercaseName + "*"; - @SuppressWarnings("unchecked") - List components = (List) index.apply(graph, indexRoot, search, Integer.MAX_VALUE); - - Set rs = new THashSet(); - for (Resource componentResult : components) { - if (DEBUG_INDEX_SEARCH) - System.out.println(getClass().getSimpleName() + ": found " + componentResult); - String n = graph.getPossibleRelatedValue(componentResult, L0.HasName, Bindings.STRING); - if (n != null && n.toLowerCase().equals(lowercaseName)) - rs.add(componentResult); - } - - Cache c = getCache(graph, indexRoot); - - if(rs.size() == 0) { - if(!c.getRequested().contains(name)) { - c.addRequested(name); - return name; - } - } else if(rs.size() == 1) { - if(component.equals(rs.iterator().next())) { - return name; - } - } - - } - - } - - } - - } - - StructuralResource2 STR = StructuralResource2.getInstance(graph); - Resource container = graph.getSingleObject(component, L0.PartOf); - Resource componentType = graph.getSingleType(component, STR.Component); - return validateInstanceName(graph, configurationRoot, container, componentType, proposition, acceptProposition); - - } - - static class ComponentsRequest extends UnaryRead>{ - - public ComponentsRequest(Tuple4 parameter) { - super(parameter); - } - - @Override - public Set perform(ReadGraph graph) throws DatabaseException { - - Resource indexRoot = (Resource)parameter.get(0); - Function index = (Function)parameter.get(1); - String search = (String)parameter.get(2); - Comparator comparator = (Comparator)parameter.get(3); - - List components = (List) index.apply(graph, indexRoot, search, Integer.MAX_VALUE); - Set reserved = new TreeSet(comparator); - - Layer0 L0 = Layer0.getInstance(graph); - for (Resource componentResult : components) { - if (DEBUG_INDEX_SEARCH) - System.out.println(getClass().getSimpleName() + ": found " + componentResult); - String name = graph.getPossibleRelatedValue(componentResult, L0.HasName, Bindings.STRING); - if (name != null) - reserved.add(name); - } - - System.err.println("found " + reserved.size() + " components"); - - return reserved; - - } - - } - - @Override - public String validateInstanceName(ReadGraph graph, Resource configurationRoot, Resource container, - Resource componentType, String proposition, boolean acceptProposition) throws NamingException, DatabaseException { - Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(configurationRoot)); - if (indexRoot == null) { - System.err.println("Could not find index root from configuration root '" + NameUtils.getSafeName(graph, configurationRoot, true) + "'"); - if(fallbackStrategy == null) - fallbackStrategy = - new CaseInsensitiveComponentNamingStrategy2(graph.getService(GraphChangeListenerSupport.class), generatedNameFormat); - return fallbackStrategy.validateInstanceName(graph, configurationRoot, container, componentType, proposition, acceptProposition); - } - - if (propositionPreFilter != null) - proposition = propositionPreFilter.apply(proposition); - - synchronized (this) { - - String search = "Name:" + proposition + "*"; - - Set reserved = graph.syncRequest(new ComponentsRequest(new Tuple4(indexRoot, index, search, getComparator())), TransientCacheAsyncListener.instance()); - - Cache cache = getCache(graph, indexRoot); - - findStartsWithMatches(cache.getRequested(), proposition, reserved); - - String result = findFreshName(reserved, proposition, acceptProposition); - cache.addRequested(result); - - if (DEBUG_INDEX_SEARCH) - System.out.println(getClass().getSimpleName() + ": validated instance name " + result); - - return result; - } - } - - @Override - public List validateInstanceNames( - ReadGraph graph, - Resource configurationRoot, - List propositions, - boolean acceptProposition, - Set externallyReserved) throws NamingException, DatabaseException - { - Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(configurationRoot)); - if (indexRoot == null) - throw new NamingException("Could not find index root from configuration root '" + NameUtils.getSafeName(graph, configurationRoot, true) + "'"); - - Layer0 L0 = Layer0.getInstance(graph); - - synchronized (this) { - List result = new ArrayList(propositions.size()); - Set reserved = new TreeSet(getComparator()); - - for (String proposition : propositions) { - if (propositionPreFilter != null) - proposition = propositionPreFilter.apply(proposition); - - String search = "Name:" + IndexQueries.escape( proposition ) + "*"; - @SuppressWarnings("unchecked") - List components = (List) index.apply(graph, indexRoot, search, Integer.MAX_VALUE); - - if (DEBUG_INDEX_SEARCH) - System.out.println(getClass().getSimpleName() + ": found " + components.size() - + " index results for index root " + indexRoot + " & configurationRoot " + configurationRoot - + " & proposition '" + proposition + "':"); - - reserved.clear(); - for (Resource componentResult : components) { - if (DEBUG_INDEX_SEARCH) - System.out.println(getClass().getSimpleName() + ": found " + componentResult); - String name = graph.getPossibleRelatedValue(componentResult, L0.HasName, Bindings.STRING); - if (name != null) - reserved.add(name); - } - - if (externallyReserved != null) - reserved.addAll(externallyReserved); - reserved.addAll(result); - String name = findFreshName(reserved, proposition, acceptProposition); - - result.add(name); - - if (DEBUG_INDEX_SEARCH) - System.out.println(getClass().getSimpleName() + ": validated instance name " + proposition + " -> " + name); - } - - if (DEBUG_INDEX_SEARCH) - System.out.println(getClass().getSimpleName() + ": validated instance names " + propositions + " -> " + result); - - return result; - } - } - - private Cache getCache(ReadGraph graph, Resource root) throws DatabaseException { - Cache cache = Indexing.getCache(root, Cache.class); - if(cache != null) return cache; - synchronized (this) { - cache = Indexing.getCache(root, Cache.class); - if(cache != null) return cache; - return Indexing.createCache(root, new Cache(caseInsensitive)); - } - } - - static class Cache { - - private final Set requested; - - Cache(boolean caseInsensitive) { - this.requested = new TreeSet(getComparator(caseInsensitive)); - } - - public Set getRequested() { - return requested; - } - - public void addRequested(String name) { - requested.add(name); - } - - @Override - public String toString() { - return getClass().getSimpleName() + ": " + requested; - } - - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.modeling.services; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Formatter; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.Indexing; +import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; +import org.simantics.db.common.request.PossibleIndexRoot; +import org.simantics.db.common.request.UnaryRead; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.genericrelation.IndexQueries; +import org.simantics.db.service.GraphChangeListenerSupport; +import org.simantics.layer0.Layer0; +import org.simantics.scl.runtime.function.Function; +import org.simantics.scl.runtime.function.Function1; +import org.simantics.scl.runtime.tuple.Tuple4; +import org.simantics.structural.stubs.StructuralResource2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import gnu.trove.set.hash.THashSet; + +/** + * A component naming strategy implementation for structural models based on an + * SCL function that lists used names in a model. + * + *

+ * The type of the function is expected to be: + * ReadGraph => Resource -> String -> Integer -> List<Map<String,Object>> + * + * @author Tuukka Lehtonen + * + * @see ComponentNamingStrategy + */ +public class CaseInsensitiveComponentFunctionNamingStrategy extends ComponentNamingStrategyBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(CaseInsensitiveComponentFunctionNamingStrategy.class); + protected static final boolean DEBUG_INDEX_SEARCH = false | DEBUG_ALL; + + @SuppressWarnings("rawtypes") + private final Function index; + + /** + * A filter that is applied to all user-provided name propositions before + * processing them. + */ + private Function1 propositionPreFilter; + + /** + * Construct an index-based naming strategy with "%s %d" as the generated + * name format. See {@link Formatter} for the format specification. + * + * @param index the index function for looking up used names. The function + * must be of type + * ReadGraph => Resource -> String -> Integer -> List<Map<String,Object>> + */ + @SuppressWarnings("rawtypes") + public CaseInsensitiveComponentFunctionNamingStrategy(Function index) { + this("%s %d", index); + } + + /** + * Construct an index-based naming strategy with the specified format as the + * generated name format. See {@link Formatter} for the format + * specification. + * + * @param generatedNameFormat the format to use for generated names, see + * {@link Formatter} + * @param index the index function for looking up used names. The function + * must be of type + * ReadGraph => Resource -> String -> Integer -> List<Map<String,Object>> + */ + @SuppressWarnings("rawtypes") + public CaseInsensitiveComponentFunctionNamingStrategy(String generatedNameFormat, Function index) { + super(generatedNameFormat); + this.index = index; + } + + /** + * Construct an index-based naming strategy with the specified format as the + * generated name format. See {@link Formatter} for the format + * specification. + * + * @param generatedNameFormat the format to use for generated names, see + * {@link Formatter} + * @param index the index function for looking up used names. The function + * must be of type + * ReadGraph => Resource -> String -> Integer -> List<Map<String,Object>> + * @param an optional function to + */ + @SuppressWarnings("rawtypes") + public CaseInsensitiveComponentFunctionNamingStrategy(String generatedNameFormat, Function index, Function1 propositionPreFilter) { + super(generatedNameFormat); + this.index = index; + this.propositionPreFilter = propositionPreFilter; + } + + CaseInsensitiveComponentNamingStrategy2 fallbackStrategy = null; + + @Override + public String validateInstanceName(ReadGraph graph, + Resource configurationRoot, Resource component, String proposition, boolean acceptProposition) + throws NamingException, DatabaseException { + + String lowercaseProposition = proposition.toLowerCase(); + + Layer0 L0 = Layer0.getInstance(graph); + String name = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING); + if (name != null) { + + String lowercaseName = name.toLowerCase(); + if(lowercaseName.startsWith(lowercaseProposition)) { + + Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(configurationRoot)); + if (indexRoot != null) { + + synchronized (this) { + + String search = "Name:" + lowercaseName + "*"; + @SuppressWarnings("unchecked") + List components = (List) index.apply(graph, indexRoot, search, Integer.MAX_VALUE); + + Set rs = new THashSet(); + for (Resource componentResult : components) { + if (DEBUG_INDEX_SEARCH) + LOGGER.info(getClass().getSimpleName() + ": found " + componentResult); + String n = graph.getPossibleRelatedValue(componentResult, L0.HasName, Bindings.STRING); + if (n != null && n.toLowerCase().equals(lowercaseName)) + rs.add(componentResult); + } + + Cache c = getCache(graph, indexRoot); + + if(rs.size() == 0) { + if(!c.getRequested().contains(name)) { + c.addRequested(name); + return name; + } + } else if(rs.size() == 1) { + if(component.equals(rs.iterator().next())) { + return name; + } + } + + } + + } + + } + + } + + StructuralResource2 STR = StructuralResource2.getInstance(graph); + Resource container = graph.getSingleObject(component, L0.PartOf); + Resource componentType = graph.getSingleType(component, STR.Component); + return validateInstanceName(graph, configurationRoot, container, componentType, proposition, acceptProposition); + + } + + static class ComponentsRequest extends UnaryRead>{ + + public ComponentsRequest(Tuple4 parameter) { + super(parameter); + } + + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + + Resource indexRoot = (Resource)parameter.get(0); + Function index = (Function)parameter.get(1); + String search = (String)parameter.get(2); + Comparator comparator = (Comparator)parameter.get(3); + + List components = (List) index.apply(graph, indexRoot, search, Integer.MAX_VALUE); + Set reserved = new TreeSet(comparator); + + Layer0 L0 = Layer0.getInstance(graph); + for (Resource componentResult : components) { + if (DEBUG_INDEX_SEARCH) + LOGGER.info(getClass().getSimpleName() + ": found " + componentResult); + String name = graph.getPossibleRelatedValue(componentResult, L0.HasName, Bindings.STRING); + if (name != null) + reserved.add(name); + } + + LOGGER.warn("found " + reserved.size() + " components"); + + return reserved; + + } + + } + + @Override + public String validateInstanceName(ReadGraph graph, Resource configurationRoot, Resource container, + Resource componentType, String proposition, boolean acceptProposition) throws NamingException, DatabaseException { + Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(configurationRoot)); + if (indexRoot == null) { + LOGGER.warn("Could not find index root from configuration root '" + NameUtils.getSafeName(graph, configurationRoot, true) + "'"); + if(fallbackStrategy == null) + fallbackStrategy = + new CaseInsensitiveComponentNamingStrategy2(graph.getService(GraphChangeListenerSupport.class), generatedNameFormat); + return fallbackStrategy.validateInstanceName(graph, configurationRoot, container, componentType, proposition, acceptProposition); + } + + if (propositionPreFilter != null) + proposition = propositionPreFilter.apply(proposition); + + synchronized (this) { + + String search = "Name:" + proposition + "*"; + + Set reserved = graph.syncRequest(new ComponentsRequest(new Tuple4(indexRoot, index, search, getComparator())), TransientCacheAsyncListener.instance()); + + Cache cache = getCache(graph, indexRoot); + + findStartsWithMatches(cache.getRequested(), proposition, reserved); + + String result = findFreshName(reserved, proposition, acceptProposition); + cache.addRequested(result); + + if (DEBUG_INDEX_SEARCH) + LOGGER.info(getClass().getSimpleName() + ": validated instance name " + result); + + return result; + } + } + + @Override + public List validateInstanceNames( + ReadGraph graph, + Resource configurationRoot, + List propositions, + boolean acceptProposition, + Set externallyReserved) throws NamingException, DatabaseException + { + Resource indexRoot = graph.syncRequest(new PossibleIndexRoot(configurationRoot)); + if (indexRoot == null) + throw new NamingException("Could not find index root from configuration root '" + NameUtils.getSafeName(graph, configurationRoot, true) + "'"); + + Layer0 L0 = Layer0.getInstance(graph); + + synchronized (this) { + List result = new ArrayList(propositions.size()); + Set reserved = new TreeSet(getComparator()); + + for (String proposition : propositions) { + if (propositionPreFilter != null) + proposition = propositionPreFilter.apply(proposition); + + String search = "Name:" + IndexQueries.escape( proposition ) + "*"; + @SuppressWarnings("unchecked") + List components = (List) index.apply(graph, indexRoot, search, Integer.MAX_VALUE); + + if (DEBUG_INDEX_SEARCH) + LOGGER.info(getClass().getSimpleName() + ": found " + components.size() + + " index results for index root " + indexRoot + " & configurationRoot " + configurationRoot + + " & proposition '" + proposition + "':"); + + reserved.clear(); + for (Resource componentResult : components) { + if (DEBUG_INDEX_SEARCH) + LOGGER.info(getClass().getSimpleName() + ": found " + componentResult); + String name = graph.getPossibleRelatedValue(componentResult, L0.HasName, Bindings.STRING); + if (name != null) + reserved.add(name); + } + + if (externallyReserved != null) + reserved.addAll(externallyReserved); + reserved.addAll(result); + String name = findFreshName(reserved, proposition, acceptProposition); + + result.add(name); + + if (DEBUG_INDEX_SEARCH) + LOGGER.info(getClass().getSimpleName() + ": validated instance name " + proposition + " -> " + name); + } + + if (DEBUG_INDEX_SEARCH) + LOGGER.info(getClass().getSimpleName() + ": validated instance names " + propositions + " -> " + result); + + return result; + } + } + + private Cache getCache(ReadGraph graph, Resource root) throws DatabaseException { + Cache cache = Indexing.getCache(root, Cache.class); + if(cache != null) return cache; + synchronized (this) { + cache = Indexing.getCache(root, Cache.class); + if(cache != null) return cache; + return Indexing.createCache(root, new Cache(caseInsensitive)); + } + } + + static class Cache { + + private final Set requested; + + Cache(boolean caseInsensitive) { + this.requested = new TreeSet(getComparator(caseInsensitive)); + } + + public Set getRequested() { + return requested; + } + + public void addRequested(String name) { + requested.add(name); + } + + @Override + public String toString() { + return getClass().getSimpleName() + ": " + requested; + } + + } + +}