package org.openslx.imagemaster.db.mappers; import java.nio.ByteBuffer; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.ImageDetailsRead; import org.openslx.bwlp.thrift.iface.ImagePermissions; import org.openslx.bwlp.thrift.iface.ImagePublishData; import org.openslx.bwlp.thrift.iface.ImageSummaryRead; import org.openslx.bwlp.thrift.iface.ImageVersionDetails; import org.openslx.bwlp.thrift.iface.InvocationError; import org.openslx.bwlp.thrift.iface.ShareMode; import org.openslx.bwlp.thrift.iface.TInvocationException; import org.openslx.bwlp.thrift.iface.TNotFoundException; import org.openslx.imagemaster.Globals; import org.openslx.imagemaster.db.Database; import org.openslx.imagemaster.db.MysqlConnection; import org.openslx.imagemaster.db.MysqlStatement; import org.openslx.imagemaster.db.Paginator; import org.openslx.thrifthelper.ImagePublishDataEx; import org.openslx.util.Util; /** * Representing an image in the database. * Is used to modify/update database entries. */ public class DbImage { private static final Logger LOGGER = Logger.getLogger( DbImage.class ); private static final ImagePermissions emptyPermissions = new ImagePermissions(); public static ImagePublishDataEx getImageVersion( String imageVersionId ) throws SQLException { try ( MysqlConnection connection = Database.getConnection() ) { MysqlStatement stmt = connection.prepareStatement( "SELECT v.imageversionid, v.imagebaseid, v.createtime, v.filesize, v.filepath," + " v.uploaderid, v.isvalid, v.virtualizerconfig, b.displayname, b.description, b.osid, b.virtid, b.ownerid, b.istemplate" + " FROM imageversion v INNER JOIN imagebase b USING (imagebaseid)" + " WHERE v.imageversionid = :imageversionid" ); stmt.setString( "imageversionid", imageVersionId ); ResultSet rs = stmt.executeQuery(); if ( !rs.next() ) return null; ImagePublishDataEx img = new ImagePublishDataEx(); img.imageVersionId = rs.getString( "imageversionid" ); img.imageBaseId = rs.getString( "imagebaseid" ); img.createTime = rs.getLong( "createtime" ); img.fileSize = rs.getLong( "filesize" ); img.uploader = DbUser.getUserInfoOrNull( connection, rs.getString( "uploaderid" ) ); img.imageName = rs.getString( "displayname" ); img.description = rs.getString( "description" ); img.osId = rs.getInt( "osid" ); img.virtId = rs.getString( "virtid" ); img.owner = DbUser.getUserInfoOrNull( connection, rs.getString( "ownerid" ) ); img.isTemplate = rs.getBoolean( "istemplate" ); img.machineDescription = ByteBuffer.wrap( rs.getBytes( "virtualizerconfig" ) ); // Ex img.exImagePath = rs.getString( "filepath" ); img.exIsValid = rs.getBoolean( "isvalid" ); return img; } catch ( SQLException e ) { LOGGER.error( "Query failed in DbImage.getImageVersion()", e ); throw e; } } public static void createImageBase( ImagePublishData img ) throws TInvocationException { // Input seems valid try ( MysqlConnection connection = Database.getConnection() ) { MysqlStatement stmt = connection.prepareStatement( "SELECT virtid FROM imagebase WHERE imagebaseid = :baseid" ); stmt.setString( "baseid", img.imageBaseId ); ResultSet rs = stmt.executeQuery(); if ( rs.next() ) { if ( !img.virtId.equals( rs.getString( "virtid" ) ) ) { throw new TInvocationException( InvocationError.INVALID_DATA, "Virtualizer id mismatch" ); } MysqlStatement stmt2 = connection.prepareStatement( "UPDATE imagebase SET" + " displayname = :displayname, updaterid = :updaterid," + " description = :description, osid = :osid, updatetime = UNIX_TIMESTAMP()," + " istemplate = :istemplate WHERE imagebaseid = :baseid" ); stmt2.setString( "baseid", img.imageBaseId ); stmt2.setString( "displayname", img.imageName ); stmt2.setString( "updaterid", img.uploader.userId ); stmt2.setString( "description", img.description ); stmt2.setInt( "osid", img.osId ); stmt2.setBoolean( "istemplate", img.isTemplate ); stmt2.executeUpdate(); } else { MysqlStatement stmt2 = connection.prepareStatement( "INSERT INTO imagebase" + " (imagebaseid, latestversionid, displayname, description, osid," + " virtid, createtime, updatetime, ownerid, updaterid, istemplate)" + " VALUES " + " (:imagebaseid, NULL, :displayname, :description, :osid," + " :virtid, :createtime, UNIX_TIMESTAMP(), :ownerid, :updaterid, :istemplate)" ); stmt2.setString( "imagebaseid", img.imageBaseId ); stmt2.setString( "displayname", img.imageName ); stmt2.setString( "description", img.description ); stmt2.setInt( "osid", img.osId ); stmt2.setString( "virtid", img.virtId ); stmt2.setLong( "createtime", img.createTime ); stmt2.setString( "ownerid", img.owner.userId ); stmt2.setString( "updaterid", img.uploader.userId ); stmt2.setBoolean( "istemplate", img.isTemplate ); stmt2.executeUpdate(); } connection.commit(); } catch ( SQLException e ) { LOGGER.error( "Query failed in DbImage.createImageBase()", e ); throw new TInvocationException( InvocationError.INTERNAL_SERVER_ERROR, "Database boo-boo" ); } } public static void createImageVersion( ImagePublishData img, String relLocalPath ) throws SQLException { try ( MysqlConnection connection = Database.getConnection() ) { // Insert version MysqlStatement verStmt = connection.prepareStatement( "INSERT INTO imageversion" + " (imageversionid, imagebaseid, createtime, expiretime, filesize," + " filepath, uploaderid, isvalid, isprocessed, mastersha1, virtualizerconfig)" + " VALUES " + " (:imageversionid, :imagebaseid, :createtime, :expiretime, :filesize," + " :filepath, :uploaderid, 0, 0, NULL, :virtualizerconfig)" ); verStmt.setString( "imageversionid", img.imageVersionId ); verStmt.setString( "imagebaseid", img.imageBaseId ); verStmt.setLong( "createtime", img.createTime ); verStmt.setLong( "expiretime", Util.unixTime() + Globals.getImageValiditySeconds() ); verStmt.setLong( "filesize", img.fileSize ); verStmt.setString( "filepath", relLocalPath ); verStmt.setString( "uploaderid", img.uploader.userId ); verStmt.setBinary( "virtualizerconfig", img.getMachineDescription() ); verStmt.execute(); connection.commit(); } catch ( SQLException e ) { LOGGER.error( "Query failed in DbImage.createImageVersion()", e ); throw e; } } public static void markValid( String imageVersionId, boolean isValid ) throws SQLException { try ( MysqlConnection connection = Database.getConnection() ) { MysqlStatement stmt = connection.prepareStatement( "UPDATE imageversion" + " SET isvalid = :isvalid WHERE imageversionid = :imageversionid" ); stmt.setBoolean( "isvalid", isValid ); stmt.setString( "imageversionid", imageVersionId ); stmt.executeUpdate(); updateLatestForVersion( connection, imageVersionId ); connection.commit(); } catch ( SQLException e ) { LOGGER.error( "Query failed in DbImage.markValid()", e ); throw e; } } private static void updateLatestForVersion( MysqlConnection connection, String imageVersionId ) throws SQLException { MysqlStatement stmt = connection.prepareStatement( "SELECT imagebaseid FROM imageversion" + " WHERE imageversionid = :imageversionid" ); stmt.setString( "imageversionid", imageVersionId ); ResultSet rs = stmt.executeQuery(); if ( !rs.next() ) return; updateLatestForBase( connection, rs.getString( "imagebaseid" ) ); } private static void updateLatestForBase( MysqlConnection connection, String imageBaseId ) throws SQLException { MysqlStatement stmt = connection.prepareStatement( "SELECT imageversionid FROM imageversion" + " WHERE isvalid <> 0 AND expiretime > UNIX_TIMESTAMP() AND imagebaseid = :imagebaseid" + " ORDER BY createtime DESC LIMIT 1" ); stmt.setString( "imagebaseid", imageBaseId ); ResultSet rs = stmt.executeQuery(); String latestVersionId = null; if ( rs.next() ) { latestVersionId = rs.getString( "imageversionid" ); } MysqlStatement updateLatestRef = connection.prepareStatement( "UPDATE imagebase SET latestversionid = :latestversionid" + " WHERE imagebaseid = :imagebaseid" ); updateLatestRef.setString( "latestversionid", latestVersionId ); updateLatestRef.setString( "imagebaseid", imageBaseId ); updateLatestRef.executeUpdate(); MysqlStatement expireStmt = connection.prepareStatement( "UPDATE imageversion SET expiretime = :expiretime" + " WHERE imagebaseid = :imagebaseid AND imageversionid <> :latestversionid" ); expireStmt.setString( "imagebaseid", imageBaseId ); expireStmt.setString( "latestversionid", latestVersionId ); expireStmt.setLong( "expiretime", Util.unixTime() + Globals.getOldImageExpireTimeSeconds() ); expireStmt.executeUpdate(); } public static List getPublicList( int page ) throws SQLException, TInvocationException { if ( page < 0 ) throw new TInvocationException( InvocationError.INVALID_DATA, "page must be >= 0" ); try ( MysqlConnection connection = Database.getConnection() ) { MysqlStatement stmt = connection.prepareStatement( "SELECT v.imageversionid, v.imagebaseid, v.createtime, v.filesize," + " v.uploaderid, b.displayname, b.description, b.osid, b.virtid, b.ownerid, b.istemplate FROM imagebase b" + " INNER JOIN imageversion v ON (b.latestversionid = v.imageversionid)" + " WHERE v.isvalid = 1" + " ORDER BY imageversionid " + Paginator.limitStatement( page ) ); ResultSet rs = stmt.executeQuery(); List list = new ArrayList<>(); while ( rs.next() ) { ImageSummaryRead img = new ImageSummaryRead(); img.createTime = rs.getLong( "createtime" ); //img.description = rs.getString( "description" ); img.fileSize = rs.getLong( "filesize" ); img.imageBaseId = rs.getString( "imagebaseid" ); img.imageName = rs.getString( "displayname" ); img.latestVersionId = rs.getString( "imageversionid" ); img.isTemplate = rs.getBoolean( "istemplate" ); img.osId = rs.getInt( "osid" ); img.ownerId = rs.getString( "ownerid" ); //img.software = rs.get( "" ); TODO //img.tags = rs.get( "" ); TODO img.uploaderId = rs.getString( "uploaderid" ); img.virtId = rs.getString( "virtid" ); img.userPermissions = emptyPermissions; img.defaultPermissions = emptyPermissions; list.add( img ); } return list; } catch ( SQLException e ) { LOGGER.error( "Query failed in DbImage.getPublicList()", e ); throw e; } } protected static List getImageVersions( MysqlConnection connection, String imageBaseId ) throws SQLException { List versionList = new ArrayList<>(); MysqlStatement stmt = connection.prepareStatement( "SELECT" + " imageversionid, createtime, expiretime, filesize, uploaderid," + " isprocessed FROM imageversion" + " WHERE imagebaseid = :imagebaseid AND isvalid = 1" ); stmt.setString( "imagebaseid", imageBaseId ); ResultSet rs = stmt.executeQuery(); while ( rs.next() ) { List software = null; // DbSoftwareTag.getImageVersionSoftwareList(connection, imageVersionId); String imageVersionId = rs.getString( "imageversionid" ); versionList.add( new ImageVersionDetails( imageVersionId, rs.getLong( "createtime" ), rs.getLong( "expiretime" ), rs.getLong( "filesize" ), rs.getString( "uploaderid" ), true, true, rs.getBoolean( "isprocessed" ), software ) ); } stmt.close(); return versionList; } public static ImageDetailsRead getImageDetails( String imageBaseId ) throws TNotFoundException, SQLException { try ( MysqlConnection connection = Database.getConnection() ) { MysqlStatement stmt = connection.prepareStatement( "SELECT i.imagebaseid, i.latestversionid, i.displayname," + " i.description, i.osid, i.virtid, i.createtime, i.updatetime, i.ownerid, i.updaterid, i.istemplate" + " FROM imagebase i" + " WHERE i.imagebaseid = :imagebaseid" ); stmt.setString( "imagebaseid", imageBaseId ); ResultSet rs = stmt.executeQuery(); if ( !rs.next() ) throw new TNotFoundException(); // Exists: List tags = null; // DbSoftwareTag.getImageTags(connection, imageBaseId); List versions = getImageVersions( connection, imageBaseId ); ImageDetailsRead image = new ImageDetailsRead( rs.getString( "imagebaseid" ), rs.getString( "latestversionid" ), versions, rs.getString( "displayname" ), rs.getString( "description" ), tags, rs.getInt( "osid" ), rs.getString( "virtid" ), rs.getLong( "createtime" ), rs.getLong( "updatetime" ), rs.getString( "ownerid" ), rs.getString( "updaterid" ), ShareMode.FROZEN, rs.getBoolean( "istemplate" ), emptyPermissions ); image.userPermissions = emptyPermissions; return image; } catch ( SQLException e ) { LOGGER.error( "Query failed in DbImage.getImageDetails()", e ); throw e; } } }