/* * Hibernate, Relational Persistence for Idiomatic Java * * JBoss, Home of Professional Open Source * Copyright 2012 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * * 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, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * 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, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.hibernate.ogm.dialect.mongodb; import java.util.HashSet; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import org.hibernate.ogm.datastore.spi.TupleSnapshot; import com.mongodb.DBObject; import org.hibernate.ogm.grid.EntityKey; import org.hibernate.ogm.grid.RowKey; import static org.hibernate.ogm.dialect.mongodb.MongoHelpers.getValueFromColumns; /** * @author Guillaume Scheibel <guillaume.scheibel@gmail.com> */ public class MongoDBTupleSnapshot implements TupleSnapshot { private final DBObject dbObject; public static final Pattern EMBEDDED_FIELDNAME_SEPARATOR = Pattern.compile( "\\." ); private final RowKey rowKey; private final EntityKey entityKey; //use it so it avoids multiple calls to Arrays.asList() private final List<String> columnNames; //consider RowKey columns and values as aprt of the Tuple public MongoDBTupleSnapshot(DBObject dbObject, RowKey rowKey) { this.dbObject = dbObject; this.rowKey = rowKey; this.entityKey = null; this.columnNames = null; } public MongoDBTupleSnapshot(DBObject dbObject, EntityKey entityKey) { this.dbObject = dbObject; this.entityKey = entityKey; this.columnNames = Arrays.asList( entityKey.getColumnNames()); this.rowKey = null; } @Override public Object get(String column) { if ( rowKey != null && ! isEmpty() ) { Object result = getValueFromColumns( column, rowKey.getColumnNames(), rowKey.getColumnValues() ); if ( result != null ) { return result; } } if ( column.contains( "." ) ) { String[] fields = EMBEDDED_FIELDNAME_SEPARATOR.split( column, 0 ); return this.getObject( this.dbObject.toMap(), fields, 0 ); } else { return this.dbObject.get( column ); } } @Override public Set<String> getColumnNames() { Set<String> columns = this.dbObject.toMap().keySet(); if ( rowKey != null && ! isEmpty() ) { columns = new HashSet<String>(columns); for ( String column : rowKey.getColumnNames() ) { columns.add( column ); } } return columns; } public DBObject getDbObject() { return dbObject; } /** * The internal structure of a DBOject is like a tree. * Each embedded object is a new branch represented by a Map. * This method browses recursively all nodes and returns the leaf value */ private Object getObject(Map<?, ?> fields, String[] remainingFields, int startIndex) { if ( startIndex == remainingFields.length - 1 ) { return fields.get( remainingFields[startIndex] ); } else { Map<?, ?> subMap = (Map<?, ?>) fields.get( remainingFields[startIndex] ); if ( subMap != null ) { return this.getObject( subMap, remainingFields, ++startIndex ); } else { return null; } } } @Override public boolean isEmpty() { return this.dbObject.keySet().isEmpty(); } public boolean columnInIdField(String column) { return (this.columnNames == null) ? false : this.columnNames.contains( column ); } }