/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.isis.objectstore.jdo.datanucleus.service.support; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import javax.jdo.Extent; import javax.jdo.PersistenceManager; import javax.jdo.datastore.JDOConnection; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.datanucleus.api.jdo.JDOPersistenceManager; import org.datanucleus.query.typesafe.BooleanExpression; import org.datanucleus.query.typesafe.TypesafeQuery; import org.apache.isis.applib.FatalException; import org.apache.isis.applib.annotation.DomainService; import org.apache.isis.applib.annotation.NatureOfService; import org.apache.isis.applib.annotation.Programmatic; import org.apache.isis.core.metamodel.adapter.ObjectAdapter; import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking; import org.apache.isis.core.metamodel.services.ServicesInjector; import org.apache.isis.core.runtime.persistence.ObjectPersistenceException; import org.apache.isis.core.runtime.system.persistence.PersistenceSession; import org.apache.isis.core.runtime.system.session.IsisSessionFactory; import org.apache.isis.objectstore.jdo.applib.service.support.IsisJdoSupport; /** * This service provdes a number of utility methods to supplement/support the capabilities of the JDO Objectstore. * * <p> * This implementation has no UI and there are no other implementations of the service API, and so it is annotated * with {@link org.apache.isis.applib.annotation.DomainService}. Because it is implemented in the core, this means * that it is automatically registered and available for use; no further configuration is required. */ @DomainService( nature = NatureOfService.DOMAIN, menuOrder = "" + Integer.MAX_VALUE ) public class IsisJdoSupportImpl implements IsisJdoSupport { @Programmatic @Override public <T> T refresh(final T domainObject) { final ObjectAdapter adapter = getPersistenceSession().adapterFor(domainObject); getPersistenceSession().refreshRoot(adapter); return domainObject; } @Programmatic @Override public void ensureLoaded(final Collection<?> domainObjects) { getPersistenceSession().getPersistenceManager().retrieveAll(domainObjects); } // ////////////////////////////////////// @Programmatic @Override public List<Map<String, Object>> executeSql(final String sql) { final JDOConnection dataStoreConnection = getJdoPersistenceManager().getDataStoreConnection(); try { final Object connectionObj = dataStoreConnection.getNativeConnection(); if(!(connectionObj instanceof java.sql.Connection)) { return null; } final java.sql.Connection connection = (java.sql.Connection) connectionObj; return executeSql(connection, sql); } finally { dataStoreConnection.close(); } } @Programmatic @Override public Integer executeUpdate(final String sql) { final JDOConnection dataStoreConnection = getJdoPersistenceManager().getDataStoreConnection(); try { final Object connectionObj = dataStoreConnection.getNativeConnection(); if(!(connectionObj instanceof java.sql.Connection)) { return null; } final java.sql.Connection connection = (java.sql.Connection) connectionObj; return executeUpdate(connection, sql); } finally { dataStoreConnection.close(); } } private static List<Map<String, Object>> executeSql(final java.sql.Connection connection, final String sql) { final List<Map<String,Object>> rows = Lists.newArrayList(); try(Statement statement = connection.createStatement()) { final ResultSet rs = statement.executeQuery(sql); final ResultSetMetaData rsmd = rs.getMetaData(); while(rs.next()) { final Map<String,Object> row = Maps.newLinkedHashMap(); final int columnCount = rsmd.getColumnCount(); for(int i=0; i<columnCount; i++) { final Object val = rs.getObject(i+1); row.put(rsmd.getColumnName(i+1), val); } rows.add(row); } } catch (final SQLException ex) { throw new ObjectPersistenceException("Failed to executeSql: " + sql, ex); } return rows; } private static int executeUpdate(final java.sql.Connection connection, final String sql) { try(Statement statement = connection.createStatement()){ return statement.executeUpdate(sql); } catch (final SQLException ex) { throw new ObjectPersistenceException("Failed to executeSql: " + sql, ex); } } // ////////////////////////////////////// @Programmatic @Override public void deleteAll(final Class<?>... pcClasses) { for (final Class<?> pcClass : pcClasses) { final Extent<?> extent = getJdoPersistenceManager().getExtent(pcClass); final List<Object> instances = Lists.newArrayList(extent.iterator()); // temporarily disable concurrency checking while this method is performed try { ConcurrencyChecking.executeWithConcurrencyCheckingDisabled(new Callable<Void>() { @Override public Void call() { getJdoPersistenceManager().deletePersistentAll(instances); return null; } }); } catch (final Exception ex) { throw new FatalException(ex); } } } // ////////////////////////////////////// @Programmatic @Override public <T> List<T> executeQuery(final Class<T> cls, final BooleanExpression expression) { final TypesafeQuery<T> query = newTypesafeQuery(cls).filter(expression); return executeListAndClose(query); } @Programmatic @Override public <T> TypesafeQuery<T> newTypesafeQuery(Class<T> cls) { return ((JDOPersistenceManager)getJdoPersistenceManager()).newTypesafeQuery(cls); } private static <T> List<T> executeListAndClose(final TypesafeQuery<T> query) { final List<T> elements = query.executeList(); final List<T> list = Lists.newArrayList(elements); query.closeAll(); return list; } // ////////////////////////////////////// @javax.inject.Inject IsisSessionFactory isisSessionFactory; protected PersistenceSession getPersistenceSession() { return isisSessionFactory.getCurrentSession().getPersistenceSession(); } protected ServicesInjector getServicesInjector() { return isisSessionFactory.getServicesInjector(); } @Programmatic @Override public PersistenceManager getJdoPersistenceManager() { return getPersistenceSession().getPersistenceManager(); } }