jason
jason

Reputation: 3615

grails error PatchedDefaultFlushEventListener

I hope some one can help me out here. I am trying to create an upload program that can upload one or more mp3 files and add their attributes to a database (song title, album, etc). I'm not sure if the problems I am encountering is because of a database issue or because I don't really understand how CommonsMultipartFile works. Anyway, here is my code"

View:

<g:form name="fileupload" url="[action:'uploads',controller:'fileResource']" method="POST" enctype="multipart/form-data">        
    <span>Add files...</span>
    <input type="file" name="files" multiple>           
</g:form>

fileResource:

def uploads = {                
    Collection result = []
    if (request instanceof MultipartHttpServletRequest) {
        MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest)request;
        CommonsMultipartFile file = (CommonsMultipartFile)multiRequest.getFile("files");            
            println"one"
            moveFile(file)
            println"three"            
        result << [name: file.originalFilename, size:file.size]
    }        
    render result as JSON
}

private moveFile(CommonsMultipartFile file){
    println"two"
    try{            
        def userId = getUserId()
        def newFileName = java.util.UUID.randomUUID().toString()                    
        def userGuid = SecUser.get(userId.id).uid
        def webRootDir = servletContext.getRealPath("/")            
        File myFile = new File( webRootDir +  "/myUsers/${userGuid}/music",newFileName + ".")
        file.transferTo(myFile)
        MP3File mp3file = new MP3File(myFile);
        String    duration = mp3file.getAudioHeader().getTrackLength()
        String    bitRate = mp3file.getAudioHeader().getBitRate()
        String    encodingType = mp3file.getAudioHeader().getEncodingType()
        String    getFormat = mp3file.getAudioHeader().getFormat()
        String    trackLength = mp3file.getAudioHeader().getTrackLength()
        String    fileName = file.originalFilename
        String     artistName = ""
        String     albumName = ""
        String     songName = ""

        def getArtistId=""
        try{
            if (mp3file.hasID3v2Tag()){
                //println("has id3v2 tag")
                ID3v24Tag id3v24tag = mp3file.getID3v2TagAsv24();
                artistName = (id3v24tag.getFirst(ID3v24Frames.FRAME_ID_ARTIST).trim())
                albumName = (id3v24tag.getFirst(ID3v24Frames.FRAME_ID_ALBUM).trim())
                songName = (id3v24tag.getFirst(ID3v24Frames.FRAME_ID_TITLE).trim())
            }else if (mp3file.hasID3v1Tag()) {
                //println("has id3v1 tag")
                ID3v1Tag tag = mp3file.getID3v1Tag();
                artistName = tag.getFirst(FieldKey.ARTIST).trim()
                albumName = tag.getFirst(FieldKey.ALBUM).trim()
                songName = tag.getFirst(FieldKey.TITLE).trim()
            }
            else{
                println("this format not yet supported:" + getFormat)
            }
        }catch (Exception ex) {
            log.error("ERROR:  FILE NOT PROCESSED")
        }

        try{
            def oArtist = ""
            def c = Artist.createCriteria()
            def getMyArtist = c.get {
                eq('artistName', artistName )
                secUser {
                    eq('id', userId.id)
                }
            }
            if (getMyArtist == null){
                //artist does not exist
                //    1c.  add artist
                //    1d.  add album
                //    1e.  add song
                //    1f.  move song
                //    1g.  DONE
                oArtist=  new com.jason.score.Artist(
                    artistName : artistName    ,
                    secUser : userId.id
                )
                userId.addToArtist(oArtist).save(flush:true)
                def oAlbum     =  new Album
                (
                    albumName:        albumName
                )
                oArtist.addToAlbum(oAlbum).save(flush:true)

                def oSong = new Song
                (
                    fileLocation: webRootDir + "myUsers/${userGuid}/music/",
                    songBitRate: bitRate,
                    songDuration: duration,
                    songEncodeType: encodingType,
                    songName: songName
                )
                oAlbum.addToSong(oSong).save(flush:true)
            }else{
                //artist exists with that username
                //need album name and artist id
                def d = Album.createCriteria()
                def getMyAlbum = d.get {
                eq('albumName', albumName )
                artist {
                    eq('id', getMyArtist.id)
                }
                        }
                if(getMyAlbum == null){
                    //                3.  add album
                    //                3a.  add song
                    //                3b.  move song
                    //                3c.  DONE                                
                    Artist findArtist = Artist.get(getMyArtist.id)
                    def oAlbum     =  new Album
                    (
                        albumName:        albumName
                    )
                    findArtist.addToAlbum(oAlbum).save(flush:true)
                    def oSong = new Song
                    (
                        fileLocation: webRootDir + "myUsers/${userGuid}/music/",
                        songBitRate: bitRate,
                        songDuration: duration,
                        songEncodeType: encodingType,
                        songName: songName
                    )
                    oAlbum.addToSong(oSong).save(flush:true)
                    }else{
                        //album does exist
                        //check if song exists with album id                            
                        def e = Song.createCriteria()
                        def getMySong = e.get {
                            eq('songName', songName )
                            album {
                                eq('id', getMyAlbum.id)
                            }
                        }
                        if (getMySong==null){
                            Album findAlbum = Album.get(getMyAlbum.id)                                
                            def oSong = new Song
                            (
                                fileLocation: webRootDir + "myUsers/${userGuid}/music/",
                                songBitRate: bitRate,
                                songDuration: duration,
                                songEncodeType: encodingType,
                                songName: songName
                            )
                            findAlbum.addToSong(oSong).save(flush:true)
                        }else{
                            //it already exists, so do nothing
                        }                


                    }
                }                        
        }catch (Exception ex){
            log.error("ERROR: ADDING TO DB: " + ex)
        }
    }catch (Exception ex){
        log.error("error" + ex)
    }
}

    private getUserId(){
    return SecUser.get(springSecurityService.principal.id)
}
private getUser(){
    return SecUser.get(springSecurityService.principal)
}

The error I am getting is:

2012-01-02 14:25:25,314 [http-8080-1] ERROR events.PatchedDefaultFlushEventListener  - Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.jason.score.SecUser#1]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1792)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2435)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.codehaus.groovy.grails.orm.hibernate.events.PatchedDefaultFlushEventListener.performExecutions(PatchedDefaultFlushEventListener.java:46)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.springframework.orm.hibernate3.HibernateTemplate$28.doInHibernate(HibernateTemplate.java:883)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.flush(HibernateTemplate.java:881)
at org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod$1.doInHibernate(SavePersistentMethod.java:58)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:406)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339)
at org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod.performSave(SavePersistentMethod.java:53)
at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod.doInvokeInternal(AbstractSavePersistentMethod.java:179)
at org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod.invoke(AbstractDynamicPersistentMethod.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSite.invoke(PojoMetaMethodSite.java:188)
....

2012-01-02 14:25:25,379 [http-8080-1] ERROR errors.GrailsExceptionResolver - Exception occurred when processing request: [POST] /com.jason.score/fileResource/uploads Stacktrace follows: org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [com.jason.score.SecUser] with identifier [1]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.jason.score.SecUser#1] at java.lang.Thread.run(Thread.java:662) Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.jason.score.SecUser#1] ... 1 more

Upvotes: 1

Views: 2071

Answers (1)

The error is due to Hibernate. There is likely an error in your criteria queries. This looks like a likely candidate

oAlbum.addToSong(oSong).save(flush:true)

Those should be separate operations. The criteria queries should be encapsulated by methods in the service layer. For operations this simple, you probably won't see much benefit from using criteria over GORM's dynamic finders.

You're also trying to do way too much in one place. Refactor your controller to use a service to do these operations. Break moveFile() up into multiple methods to parse the MP3File, then pass that to another method to add it to the user's songs.

You shouldn't need to use the user's ID if you create the relationship directly in the domain.

Write some tests for each atomic piece and it should make the error easier to find.

Upvotes: 1

Related Questions