001package net.filebot.cli; 002 003import java.io.File; 004 005import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; 006 007import groovy.lang.Closure; 008 009import net.filebot.InvalidInputException; 010import net.filebot.RenameAction; 011import net.filebot.util.FileUtilities; 012 013public class GroovyAction implements RenameAction, ConflictAction { 014 015 private final String name; 016 private final String code; 017 018 // compile on demand 019 private transient Closure<?> closure; 020 021 public GroovyAction(String name, String code) { 022 this.name = name; 023 this.code = code; 024 this.closure = null; 025 } 026 027 public GroovyAction(String name, String code, Closure<?> closure) { 028 this.name = name; 029 this.code = code; 030 this.closure = closure; 031 } 032 033 private synchronized Closure<?> compile() { 034 // compile on demand 035 if (closure == null) { 036 try { 037 closure = new ScriptShell().callable(code); 038 } catch (Throwable e) { 039 throw new InvalidInputException("Invalid Groovy action", e); 040 } 041 } 042 return closure; 043 } 044 045 @Override 046 public File conflict(File from, File to) throws Exception { 047 return apply(from, to); 048 } 049 050 @Override 051 public File rename(File from, File to) throws Exception { 052 return apply(from, to); 053 } 054 055 public File apply(File from, File to) throws Exception { 056 Object result = compile().call(from, to); 057 058 // conflict: skip this file 059 // rename: remote target file 060 if (result == null) { 061 return null; 062 } 063 064 // conflict: confirm target file 065 // rename: local target file 066 if (result instanceof File) { 067 return FileUtilities.resolveSibling(to, (File) result); 068 } 069 070 // conflict: confirm target file 071 // rename: local target file 072 if (result instanceof CharSequence) { 073 return FileUtilities.resolveSibling(to, new File(result.toString())); 074 } 075 076 // GroovyCastException: Cannot cast object 'X' with class 'java.lang.String' to class 'java.io.File' 077 return (File) DefaultTypeTransformation.castToType(result, File.class); 078 } 079 080 @Override 081 public String toString() { 082 return name; 083 } 084 085 public static GroovyAction wrap(Closure<?> closure) { 086 return new GroovyAction("CLOSURE", null, closure); 087 } 088 089}