All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.tool.ide.completion.ConfigurationCompletion Maven / Gradle / Ivy

There is a newer version: 7.0.0.Beta1
Show newest version
package org.hibernate.tool.ide.completion;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.boot.Metadata;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.OneToMany;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.tool.internal.export.java.Cfg2JavaTool;
import org.hibernate.tool.internal.export.java.EntityPOJOClass;

/**
 * @author Max Rydahl Andersen
 *
 */
public class ConfigurationCompletion {

	private final Metadata metadata;

	public ConfigurationCompletion(Metadata md) {
		this.metadata = md;
	}

	public void getMatchingImports(String prefix , IHQLCompletionRequestor collector) {
		getMatchingImports( prefix, prefix.length() , collector );
	}
	
	public void getMatchingImports(String prefix, int cursorPosition, IHQLCompletionRequestor collector) {
		Iterator> iterator = metadata.getImports().entrySet().iterator();
		while ( iterator.hasNext() ) {
			Entry entry = iterator.next();
			String entityImport = (String) entry.getKey();
			String entityName = (String) entry.getValue();
			
			if(entityImport.toLowerCase().startsWith(prefix.toLowerCase())) {
				HQLCompletionProposal proposal = createStartWithCompletionProposal( prefix, cursorPosition, HQLCompletionProposal.ENTITY_NAME, entityImport );
				proposal.setShortEntityName( entityImport );
				proposal.setEntityName( entityName );
				collector.accept(proposal);				
								
			}
		}		
	}
	
	public void getMatchingKeywords(String prefix, int cursorPosition, IHQLCompletionRequestor collector) {
		findMatchingWords( cursorPosition, prefix, HQLAnalyzer.getHQLKeywords(), HQLCompletionProposal.KEYWORD, collector);
	}

	public void getMatchingFunctions(String prefix, int cursorPosition, IHQLCompletionRequestor collector) {
		findMatchingWords( cursorPosition, prefix, HQLAnalyzer.getHQLFunctionNames(), HQLCompletionProposal.FUNCTION, collector);
	}
	
	public void getMatchingProperties(String path, String prefix, IHQLCompletionRequestor hcc) {
		getMatchingProperties( path, prefix, prefix.length(), hcc );
	}
	
	public void getMatchingProperties(String path, String prefix, int cursorPosition, IHQLCompletionRequestor hcc) {
		int idx = path.indexOf('/');
        if (idx == -1) { // root name
            PersistentClass cmd = getPersistentClass(path);
            if (cmd == null) {
                return;
            }
            addPropertiesToList(cmd, prefix, cursorPosition, hcc);            
        } else {
            String baseEntityName = path.substring(0, idx);
            String propertyPath = path.substring(idx + 1);
            Value value = getNextAttributeType(baseEntityName, propertyPath);
            if (value == null) {
                return;
            }
            
            // Go to the next property (get the y of x/y/z when root is x)
            idx = propertyPath.indexOf('/');
            if (idx == -1) {
                path = "";
            } else {
                path = propertyPath.substring(idx + 1);
            }
            if (path.length() == 0) {
                // No properties left
                if (value instanceof Component) {
                    addPropertiesToList((Component) value, prefix, cursorPosition, hcc);
                } else if (value instanceof Collection && ((Collection)value).getElement() instanceof Component) {
                	addPropertiesToList((Component) ((Collection)value).getElement(), prefix, cursorPosition, hcc);
                } else {
                	 addPropertiesToList(getPersistentClass( getReferencedEntityName( value ) ), prefix, cursorPosition, hcc);
                }
            } else {
                // Nested properties
                if (value instanceof Component) {
                    // We need to find the first non-component type 
                    while (value instanceof Component && path.length() > 0) {
                        value = getNextAttributeType((Component) value, path);
                        if (value != null) {
                            // Consume part of the canonical path
                            idx = path.indexOf('/');
                            if (idx != -1) {
                                path = path.substring(idx + 1);
                            } else {
                                path = "";
                            }
                        }
                    }
                    if (value instanceof Component) {
                        addPropertiesToList((Component) value, prefix, cursorPosition, hcc);
                    } else if (value != null) {
                        if (path.length() > 0) {
                            path = getReferencedEntityName( value ) + "/" + path;
                        } else {
                            path = getReferencedEntityName( value );
                        }
                        getMatchingProperties( path, prefix, cursorPosition, hcc );
                    }
                } else {
                    // Just call the method recursively to add our new type
                    getMatchingProperties(getReferencedEntityName( value ) + "/" + path, prefix, cursorPosition, hcc);
                }
            }
        }
	}

	private String getReferencedEntityName(Value value) {
		if(value instanceof ToOne) {
			return ((ToOne)value).getReferencedEntityName();
		}
		if ( value instanceof Collection ) {
			Collection collection = ((Collection)value);
			Value element = collection.getElement();
			String elementType = getReferencedEntityName( element );
			if(collection.isIndexed()) {
				//TODO..list/map
				/*IndexedCollection idxCol = (IndexedCollection) collection;
				if(!idxCol.isList()) {
					Value idxElement = idxCol.getIndex();
					String indexType = getReferencedEntityName( value );
					genericDecl = indexType + "," + elementType;
				}*/
			} 			
			return elementType;
		}
		
		if(value instanceof OneToMany) {
			return ((OneToMany)value).getReferencedEntityName();
		}
		
		return null;
	}

	private void addPropertiesToList(PersistentClass cmd, String prefix, int cursorPosition, IHQLCompletionRequestor hcc) {
		if (cmd == null) {
            return;
        }
        if (prefix == null) {
            prefix = "";
        }
        
        // Add superclass's properties too
        while (cmd != null){
        	EntityPOJOClass pc = new EntityPOJOClass(cmd, new Cfg2JavaTool()); // TODO: we should extract the needed functionallity from this hbm2java class.
            
        	Iterator allPropertiesIterator = pc.getAllPropertiesIterator();
            while ( allPropertiesIterator.hasNext() ) {
    			Property property = allPropertiesIterator.next();
    			String candidate = property.getName();
    		    if (prefix.length() == 0 || candidate.toLowerCase().startsWith(prefix.toLowerCase())) {
    		    	HQLCompletionProposal proposal = createStartWithCompletionProposal( prefix, cursorPosition, HQLCompletionProposal.PROPERTY, candidate );
    		    	proposal.setEntityName( cmd.getEntityName() );
    		    	proposal.setProperty( property );
    		    	proposal.setPropertyName( candidate );		    	
    				hcc.accept( proposal);		    	                
                }
            }
            cmd = cmd.getSuperclass();
        }
           	
	}

	private HQLCompletionProposal createStartWithCompletionProposal(String prefix, int cursorPosition, int kind, String candidate) {
		HQLCompletionProposal proposal = new HQLCompletionProposal(kind, cursorPosition);
		if(candidate.startsWith(prefix)) {
			proposal.setCompletion( candidate.substring(prefix.length()) );
			proposal.setSimpleName( candidate );
			proposal.setReplaceStart( cursorPosition );	
			proposal.setReplaceEnd( cursorPosition );
		} else {
			proposal.setCompletion( candidate );
			proposal.setSimpleName( candidate );
			proposal.setReplaceStart( cursorPosition  - prefix.length() );// replace prefix	
			proposal.setReplaceEnd( cursorPosition ); 	
		}
		return proposal;
	}

	/** returns PersistentClass for path. Can be null if path is an imported non-mapped class */
	private PersistentClass getPersistentClass(String path) {
		if(path==null) return null;
		String entityName = (String) metadata.getImports().get( path );
		if(entityName==null) {
			return metadata.getEntityBinding(path);
		} else {
			return metadata.getEntityBinding(entityName);
		}	
	}

	public String getCanonicalPath(List qts, String name) {
		Map alias2Type = new HashMap();
        for (Iterator iter = qts.iterator(); iter.hasNext();) {
			EntityNameReference qt = iter.next();
            alias2Type.put(qt.getAlias(), qt.getEntityName());
        }
        if (qts.size() == 1) { 
            EntityNameReference visible = qts.get(0);
            String alias = visible.getAlias();
            if (name.equals(alias)) {
                return visible.getEntityName();
            } else if (alias == null || alias.length() == 0 || alias.equals(visible.getEntityName())) {
                return visible.getEntityName() + "/" + name;
            }
        }
        return getCanonicalPath(new HashSet(), alias2Type, name);		
	}
	
	private String getCanonicalPath(Set resolved, Map alias2Type, String name) {
        if (resolved.contains(name)) {
            // To prevent a stack overflow
            return name;
        }
        resolved.add(name);
        String type = (String) alias2Type.get(name);
        if (type != null) {
            return name.equals(type) ? name : getCanonicalPath(resolved, alias2Type, type);
        }
        int idx = name.lastIndexOf('.');
        if (idx == -1) {
            return type != null ? type : name;
        }
        String baseName = name.substring(0, idx);
        String prop = name.substring(idx + 1);
        if (isAliasKnown(alias2Type, baseName)) {
            return getCanonicalPath(resolved, alias2Type, baseName) + "/" + prop;
        } else {
            return name;
        }
    }
	
	private static boolean isAliasKnown(Map alias2Type, String alias) {
        if (alias2Type.containsKey(alias)) {
            return true;
        }
        int idx = alias.lastIndexOf('.');
        if (idx == -1) {
            return false;
        }
        return isAliasKnown(alias2Type, alias.substring(0, idx));
    }
    
	private Value getNextAttributeType(String type, String attributePath) {
        PersistentClass cmd = getPersistentClass( type );
        if (cmd == null) {
            return null;
        }
        String attribute;
        int idx = attributePath.indexOf('/');
        if (idx == -1) {
            attribute = attributePath;
        } else {
            attribute = attributePath.substring(0, idx);
        }
        
        String idName = cmd.getIdentifierProperty()==null?null:cmd.getIdentifierProperty().getName();
        if (attribute.equals(idName)) {
            return cmd.getIdentifierProperty().getValue();
        }
        try {
        	Property property = cmd.getProperty( attribute );
        	return property==null?null:property.getValue();
        } catch (HibernateException he) {
        	return null;
        }
                
    }

	private Value getNextAttributeType(Component t, String attributeName) {
        int idx = attributeName.indexOf('/');
        if (idx != -1) {
            attributeName = attributeName.substring(0, idx);
        }
        Iterator names = t.getPropertyIterator();
        while ( names.hasNext() ) {
			Property element = (Property) names.next();
			String name = element.getName();
			if (attributeName.equals(name)) {
                return element.getValue();
            }
        }
        return null;
    }
	
	void addPropertiesToList(Component t, String prefix, int cursorPosition, IHQLCompletionRequestor hcc) {
        if (t == null) {
            return;
        }
        Iterator props = t.getPropertyIterator();
        while ( props.hasNext() ) {
			Property element = (Property) props.next();			
			String candidate = element.getName();
			if (candidate.toLowerCase().startsWith(prefix.toLowerCase())) {
				HQLCompletionProposal proposal = createStartWithCompletionProposal( prefix, cursorPosition, HQLCompletionProposal.PROPERTY, candidate );
				//proposal.setEntityName( cmd.getEntityName() ); ...we don't know here..TODO: pass in the "path"
		    	proposal.setPropertyName( candidate );
		    	proposal.setProperty(element);
				hcc.accept( proposal);				               
            }
        }
    }
	
	private void findMatchingWords(int cursorPosition, String prefix, String[] words, int kind, IHQLCompletionRequestor hcc) {
		int i = Arrays.binarySearch(words, prefix.toLowerCase());
		if(i<0) {
			i = Math.abs(i+1);
		}
		
		for (int cnt = i; cnt < words.length; cnt++) {
			String word = words[cnt];
			if(word.toLowerCase().startsWith(prefix.toLowerCase())) {
				HQLCompletionProposal proposal = createStartWithCompletionProposal( prefix, cursorPosition, kind, word );
				hcc.accept( proposal);				
			} else {
				break;
			}
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy