Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import org.dom4j.Element;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.query.sql.NativeSQLQueryCollectionReturn;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.query.sql.NativeSQLQueryJoinReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Value;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.ToOne;
import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory;
import org.hibernate.util.ArrayHelper;
import org.hibernate.util.CollectionHelper;
import org.hibernate.util.StringHelper;
/**
* @author Emmanuel Bernard
*/
public abstract class ResultSetMappingBinder {
/**
* Build a ResultSetMappingDefinition given a containing element for the "return-XXX" elements
*
* @param resultSetElem The element containing the return definitions.
* @param path No clue...
* @param mappings The current processing state.
* @return The description of the mappings...
*/
protected static ResultSetMappingDefinition buildResultSetMappingDefinition(Element resultSetElem, String path, Mappings mappings) {
String resultSetName = resultSetElem.attribute( "name" ).getValue();
if ( path != null ) {
resultSetName = path + '.' + resultSetName;
}
ResultSetMappingDefinition definition = new ResultSetMappingDefinition( resultSetName );
int cnt = 0;
Iterator returns = resultSetElem.elementIterator();
while ( returns.hasNext() ) {
cnt++;
Element returnElem = (Element) returns.next();
String name = returnElem.getName();
if ( "return-scalar".equals( name ) ) {
String column = returnElem.attributeValue( "column" );
String typeFromXML = HbmBinder.getTypeFromXML( returnElem );
Type type = null;
if(typeFromXML!=null) {
type = mappings.getTypeResolver().heuristicType( typeFromXML );
if ( type == null ) {
throw new MappingException( "could not determine type " + type );
}
}
definition.addQueryReturn( new NativeSQLQueryScalarReturn( column, type ) );
}
else if ( "return".equals( name ) ) {
definition.addQueryReturn( bindReturn( returnElem, mappings, cnt ) );
}
else if ( "return-join".equals( name ) ) {
definition.addQueryReturn( bindReturnJoin( returnElem, mappings ) );
}
else if ( "load-collection".equals( name ) ) {
definition.addQueryReturn( bindLoadCollection( returnElem, mappings ) );
}
}
return definition;
}
private static NativeSQLQueryRootReturn bindReturn(Element returnElem, Mappings mappings, int elementCount) {
String alias = returnElem.attributeValue( "alias" );
if( StringHelper.isEmpty(alias)) {
alias = "alias_" + elementCount; // hack/workaround as sqlquery impl depend on having a key.
}
String entityName = HbmBinder.getEntityName(returnElem, mappings);
if(entityName==null) {
throw new MappingException( " must specify either a class or entity-name");
}
LockMode lockMode = getLockMode( returnElem.attributeValue( "lock-mode" ) );
PersistentClass pc = mappings.getClass( entityName );
java.util.Map propertyResults = bindPropertyResults(alias, returnElem, pc, mappings );
return new NativeSQLQueryRootReturn(
alias,
entityName,
propertyResults,
lockMode
);
}
private static NativeSQLQueryJoinReturn bindReturnJoin(Element returnElem, Mappings mappings) {
String alias = returnElem.attributeValue( "alias" );
String roleAttribute = returnElem.attributeValue( "property" );
LockMode lockMode = getLockMode( returnElem.attributeValue( "lock-mode" ) );
int dot = roleAttribute.lastIndexOf( '.' );
if ( dot == -1 ) {
throw new MappingException(
"Role attribute for sql query return [alias=" + alias +
"] not formatted correctly {owningAlias.propertyName}"
);
}
String roleOwnerAlias = roleAttribute.substring( 0, dot );
String roleProperty = roleAttribute.substring( dot + 1 );
//FIXME: get the PersistentClass
java.util.Map propertyResults = bindPropertyResults(alias, returnElem, null, mappings );
return new NativeSQLQueryJoinReturn(
alias,
roleOwnerAlias,
roleProperty,
propertyResults, // TODO: bindpropertyresults(alias, returnElem)
lockMode
);
}
private static NativeSQLQueryCollectionReturn bindLoadCollection(Element returnElem, Mappings mappings) {
String alias = returnElem.attributeValue( "alias" );
String collectionAttribute = returnElem.attributeValue( "role" );
LockMode lockMode = getLockMode( returnElem.attributeValue( "lock-mode" ) );
int dot = collectionAttribute.lastIndexOf( '.' );
if ( dot == -1 ) {
throw new MappingException(
"Collection attribute for sql query return [alias=" + alias +
"] not formatted correctly {OwnerClassName.propertyName}"
);
}
String ownerClassName = HbmBinder.getClassName( collectionAttribute.substring( 0, dot ), mappings );
String ownerPropertyName = collectionAttribute.substring( dot + 1 );
//FIXME: get the PersistentClass
java.util.Map propertyResults = bindPropertyResults(alias, returnElem, null, mappings );
return new NativeSQLQueryCollectionReturn(
alias,
ownerClassName,
ownerPropertyName,
propertyResults,
lockMode
);
}
private static java.util.Map bindPropertyResults(
String alias, Element returnElement, PersistentClass pc, Mappings mappings
) {
HashMap propertyresults = new HashMap(); // maybe a concrete SQLpropertyresult type, but Map is exactly what is required at the moment
Element discriminatorResult = returnElement.element("return-discriminator");
if(discriminatorResult!=null) {
ArrayList resultColumns = getResultColumns(discriminatorResult);
propertyresults.put("class", ArrayHelper.toStringArray(resultColumns) );
}
Iterator iterator = returnElement.elementIterator("return-property");
List properties = new ArrayList();
List propertyNames = new ArrayList();
while ( iterator.hasNext() ) {
Element propertyresult = (Element) iterator.next();
String name = propertyresult.attributeValue("name");
if ( pc == null || name.indexOf( '.') == -1) { //if dotted and not load-collection nor return-join
//regular property
properties.add(propertyresult);
propertyNames.add(name);
}
else {
/**
* Reorder properties
* 1. get the parent property
* 2. list all the properties following the expected one in the parent property
* 3. calculate the lowest index and insert the property
*/
if (pc == null)
throw new MappingException("dotted notation in or not yet supported");
int dotIndex = name.lastIndexOf( '.' );
String reducedName = name.substring( 0, dotIndex );
Value value = pc.getRecursiveProperty( reducedName ).getValue();
Iterator parentPropIter;
if ( value instanceof Component ) {
Component comp = (Component) value;
parentPropIter = comp.getPropertyIterator();
}
else if ( value instanceof ToOne ) {
ToOne toOne = (ToOne) value;
PersistentClass referencedPc = mappings.getClass( toOne.getReferencedEntityName() );
if ( toOne.getReferencedPropertyName() != null ) {
try {
parentPropIter = ( (Component) referencedPc.getRecursiveProperty( toOne.getReferencedPropertyName() ).getValue() ).getPropertyIterator();
} catch (ClassCastException e) {
throw new MappingException("dotted notation reference neither a component nor a many/one to one", e);
}
}
else {
try {
if ( referencedPc.getIdentifierMapper() == null ) {
parentPropIter = ( (Component) referencedPc.getIdentifierProperty().getValue() ).getPropertyIterator();
}
else {
parentPropIter = referencedPc.getIdentifierMapper().getPropertyIterator();
}
}
catch (ClassCastException e) {
throw new MappingException("dotted notation reference neither a component nor a many/one to one", e);
}
}
}
else {
throw new MappingException("dotted notation reference neither a component nor a many/one to one");
}
boolean hasFollowers = false;
List followers = new ArrayList();
while ( parentPropIter.hasNext() ) {
String currentPropertyName = ( (Property) parentPropIter.next() ).getName();
String currentName = reducedName + '.' + currentPropertyName;
if (hasFollowers) {
followers.add( currentName );
}
if ( name.equals( currentName ) ) hasFollowers = true;
}
int index = propertyNames.size();
int followersSize = followers.size();
for (int loop = 0 ; loop < followersSize ; loop++) {
String follower = (String) followers.get(loop);
int currentIndex = getIndexOfFirstMatchingProperty(propertyNames, follower);
index = currentIndex != -1 && currentIndex < index ? currentIndex : index;
}
propertyNames.add(index, name);
properties.add(index, propertyresult);
}
}
Set uniqueReturnProperty = new HashSet();
iterator = properties.iterator();
while ( iterator.hasNext() ) {
Element propertyresult = (Element) iterator.next();
String name = propertyresult.attributeValue("name");
if ( "class".equals(name) ) {
throw new MappingException(
"class is not a valid property name to use in a , use instead"
);
}
//TODO: validate existing of property with the chosen name. (secondpass )
ArrayList allResultColumns = getResultColumns(propertyresult);
if ( allResultColumns.isEmpty() ) {
throw new MappingException(
"return-property for alias " + alias +
" must specify at least one column or return-column name"
);
}
if ( uniqueReturnProperty.contains( name ) ) {
throw new MappingException(
"duplicate return-property for property " + name +
" on alias " + alias
);
}
uniqueReturnProperty.add(name);
// the issue here is that for representing an entity collection,
// the collection element values (the property values of the associated entity)
// are represented as 'element.{propertyname}'. Thus the StringHelper.root()
// here puts everything under 'element' (which additionally has significant
// meaning). Probably what we need to do is to something like this instead:
// String root = StringHelper.root( name );
// String key = root; // by default
// if ( !root.equals( name ) ) {
// // we had a dot
// if ( !root.equals( alias ) {
// // the root does not apply to the specific alias
// if ( "elements".equals( root ) {
// // we specifically have a representing an entity collection
// // and this is one of that entity's properties
// key = name;
// }
// }
// }
// but I am not clear enough on the intended purpose of this code block, especially
// in relation to the "Reorder properties" code block above...
// String key = StringHelper.root( name );
String key = name;
ArrayList intermediateResults = (ArrayList) propertyresults.get( key );
if (intermediateResults == null) {
propertyresults.put( key, allResultColumns );
}
else {
intermediateResults.addAll( allResultColumns );
}
}
Iterator entries = propertyresults.entrySet().iterator();
while ( entries.hasNext() ) {
Map.Entry entry = (Map.Entry) entries.next();
if (entry.getValue() instanceof ArrayList) {
ArrayList list = (ArrayList) entry.getValue();
entry.setValue( list.toArray( new String[ list.size() ] ) );
}
}
return propertyresults.isEmpty() ? CollectionHelper.EMPTY_MAP : propertyresults;
}
private static int getIndexOfFirstMatchingProperty(List propertyNames, String follower) {
int propertySize = propertyNames.size();
for (int propIndex = 0 ; propIndex < propertySize ; propIndex++) {
if ( ( (String) propertyNames.get(propIndex) ).startsWith( follower ) ) {
return propIndex;
}
}
return -1;
}
private static ArrayList getResultColumns(Element propertyresult) {
String column = unquote(propertyresult.attributeValue("column"));
ArrayList allResultColumns = new ArrayList();
if(column!=null) allResultColumns.add(column);
Iterator resultColumns = propertyresult.elementIterator("return-column");
while ( resultColumns.hasNext() ) {
Element element = (Element) resultColumns.next();
allResultColumns.add( unquote(element.attributeValue("name")) );
}
return allResultColumns;
}
private static String unquote(String name) {
if (name!=null && name.charAt(0)=='`') {
name=name.substring( 1, name.length()-1 );
}
return name;
}
private static LockMode getLockMode(String lockMode) {
if ( lockMode == null || "read".equals( lockMode ) ) {
return LockMode.READ;
}
else if ( "none".equals( lockMode ) ) {
return LockMode.NONE;
}
else if ( "upgrade".equals( lockMode ) ) {
return LockMode.UPGRADE;
}
else if ( "upgrade-nowait".equals( lockMode ) ) {
return LockMode.UPGRADE_NOWAIT;
}
else if ( "write".equals( lockMode ) ) {
return LockMode.WRITE;
}
else if ( "force".equals( lockMode ) ) {
return LockMode.FORCE;
}
else if ( "optimistic".equals( lockMode ) ) {
return LockMode.OPTIMISTIC;
}
else if ( "optimistic_force_increment".equals( lockMode ) ) {
return LockMode.OPTIMISTIC_FORCE_INCREMENT;
}
else if ( "pessimistic_read".equals( lockMode ) ) {
return LockMode.PESSIMISTIC_READ;
}
else if ( "pessimistic_write".equals( lockMode ) ) {
return LockMode.PESSIMISTIC_WRITE;
}
else if ( "pessimistic_force_increment".equals( lockMode ) ) {
return LockMode.PESSIMISTIC_FORCE_INCREMENT;
}
else {
throw new MappingException( "unknown lockmode" );
}
}
}