/*******************************************************************************
* 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