/* * RHQ Management Platform * Copyright (C) 2005-2011 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.resource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Arrays; import java.util.List; import javax.annotation.PostConstruct; import javax.ejb.EJB; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.core.db.DatabaseType; import org.rhq.core.db.DatabaseTypeFactory; import org.rhq.core.db.H2DatabaseType; import org.rhq.core.db.OracleDatabaseType; import org.rhq.core.db.PostgresqlDatabaseType; import org.rhq.core.db.SQLServerDatabaseType; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.ResourceAvailability; import org.rhq.core.util.collection.ArrayUtils; import org.rhq.core.util.jdbc.JDBCUtil; import org.rhq.enterprise.server.RHQConstants; import org.rhq.enterprise.server.authz.AuthorizationManagerLocal; import org.rhq.enterprise.server.authz.PermissionException; /** * A manager that provides methods for manipulating and querying the cached current availability for Resources. * * @author Joseph Marques */ @Stateless public class ResourceAvailabilityManagerBean implements ResourceAvailabilityManagerLocal { private final Log log = LogFactory.getLog(ResourceAvailabilityManagerBean.class); @PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME) private EntityManager entityManager; @javax.annotation.Resource(name = "RHQ_DS", mappedName = RHQConstants.DATASOURCE_JNDI_NAME) private DataSource rhqDs; private DatabaseType dbType; @EJB private AuthorizationManagerLocal authorizationManager; @PostConstruct public void init() { dbType = DatabaseTypeFactory.getDefaultDatabaseType(); } // This is rarely needed now that we get an entry in RHQ_RESOURCE_AVAIL when the resource is persisted. But // there are upgrade scenarios ( moving up to JON 3.1) where it can still get applied. Once all customers // are on 3.1 I believe this can go away (jshaughn) // public void insertNeededAvailabilityForImportedResources(List<Integer> resourceIds) { // Hibernate didn't want to swallow ResourceAvailability.INSERT_BY_RESOURCE_IDS, so we had to go native. Connection conn = null; PreparedStatement ps = null; try { String query; if (dbType instanceof SQLServerDatabaseType) { query = "" // + "INSERT INTO RHQ_RESOURCE_AVAIL ( RESOURCE_ID, AVAILABILITY_TYPE ) " // + " SELECT res.ID, 2 " // set to UNKNOWN=2 + " FROM RHQ_RESOURCE res " // + " LEFT JOIN RHQ_RESOURCE_AVAIL avail ON res.ID = avail.RESOURCE_ID " // + " WHERE res.ID IN ( :resourceIds ) " // + " AND avail.ID IS NULL "; } else { query = "" // + "INSERT INTO RHQ_RESOURCE_AVAIL ( ID, RESOURCE_ID, AVAILABILITY_TYPE ) " // + " SELECT %s, res.ID, 2 " // set to UNKNOWN=2 + " FROM RHQ_RESOURCE res " // + " LEFT JOIN RHQ_RESOURCE_AVAIL avail ON res.ID = avail.RESOURCE_ID " // + " WHERE res.ID IN ( :resourceIds ) " // + " AND avail.ID IS NULL "; String nextValSqlFragment; if (dbType instanceof PostgresqlDatabaseType) { nextValSqlFragment = "nextval('%s_id_seq'::text)"; } else if (dbType instanceof OracleDatabaseType) { nextValSqlFragment = "%s_id_seq.nextval"; } else if (dbType instanceof H2DatabaseType) { nextValSqlFragment = "nextval('%s_id_seq')"; } else { throw new IllegalStateException("insertNeededAvailabilityForImportedResources does not support " + dbType); } String nextValSql = String.format(nextValSqlFragment, ResourceAvailability.TABLE_NAME); query = String.format(query, nextValSql); } conn = rhqDs.getConnection(); // Do one query per 1000 Resource id's to prevent Oracle from failing because of an IN clause with more // than 1000 items. int[] resourceIdArray = ArrayUtils.unwrapCollection(resourceIds); int fromIndex = 0; while (fromIndex < resourceIdArray.length) { int toIndex = (resourceIdArray.length < (fromIndex + 1000)) ? resourceIdArray.length : (fromIndex + 1000); int[] resourceIdSubArray = Arrays.copyOfRange(resourceIdArray, fromIndex, toIndex); String transformedQuery = JDBCUtil.transformQueryForMultipleInParameters(query, ":resourceIds", resourceIdSubArray.length); ps = conn.prepareStatement(transformedQuery); JDBCUtil.bindNTimes(ps, resourceIdSubArray, 1); ps.execute(); ps.close(); fromIndex = toIndex; } } catch (SQLException e) { log.warn("Could not insert cached current availabilities for newly imported Resources: " + e); } finally { JDBCUtil.safeClose(ps); JDBCUtil.safeClose(conn); } } public AvailabilityType getLatestAvailabilityType(Subject whoami, int resourceId) { if (!authorizationManager.canViewResource(whoami, resourceId)) { throw new PermissionException("User [" + whoami.getName() + "] does not have permission to view resource"); } ResourceAvailability ra = getLatestAvailability(resourceId); return (ra != null) ? ra.getAvailabilityType() : null; } public ResourceAvailability getLatestAvailability(int resourceId) { Query query = entityManager.createNamedQuery(ResourceAvailability.QUERY_FIND_BY_RESOURCE_ID); query.setParameter("resourceId", resourceId); try { ResourceAvailability result = (ResourceAvailability) query.getSingleResult(); return result; } catch (NoResultException nre) { return null; } catch (RuntimeException re) { Throwable cause = re.getCause(); if (cause instanceof SQLException) { log.error("Failed to get latest avail for Resource [" + resourceId + "]: " + JDBCUtil.convertSQLExceptionToString((SQLException) cause)); } throw re; } } public void updateAgentResourcesLatestAvailability(int agentId, AvailabilityType availabilityType, boolean isPlatform) { Query query = entityManager.createNamedQuery((isPlatform) ? ResourceAvailability.UPDATE_PLATFORM_BY_AGENT_ID : ResourceAvailability.UPDATE_CHILD_BY_AGENT_ID); query.setParameter("availabilityType", availabilityType); query.setParameter("agentId", agentId); if (!isPlatform) { query.setParameter("disabled", AvailabilityType.DISABLED); } query.executeUpdate(); } }