/* * Copyright (C) 2010-2016 JPEXS, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. */ package com.jpexs.decompiler.flash.abc.types.traits; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.types.ConvertData; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.exporters.script.Dependency; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.helpers.NulWriter; import com.jpexs.decompiler.graph.DottedChain; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author JPEXS */ public class Traits implements Cloneable, Serializable { public List<Trait> traits; public Traits() { traits = new ArrayList<>(); } public Traits(int initialCapacity) { traits = new ArrayList<>(initialCapacity); } public void delete(ABC abc, boolean d) { for (Trait t : traits) { t.delete(abc, d); } } public int addTrait(Trait t) { traits.add(t); return traits.size() - 1; } public int removeTraps(int scriptIndex, int classIndex, boolean isStatic, ABC abc, String path) throws InterruptedException { int ret = 0; for (Trait t : traits) { ret += t.removeTraps(scriptIndex, classIndex, isStatic, abc, path); } return ret; } @Override public String toString() { String s = ""; for (int t = 0; t < traits.size(); t++) { if (t > 0) { s += "\r\n"; } s += traits.get(t).toString(); } return s; } public String toString(ABC abc, List<DottedChain> fullyQualifiedNames) { String s = ""; for (int t = 0; t < traits.size(); t++) { if (t > 0) { s += "\r\n"; } s += traits.get(t).toString(abc, fullyQualifiedNames); } return s; } private class TraitConvertTask implements Callable<Void> { Trait trait; boolean makePackages; String path; ABC abc; boolean isStatic; ScriptExportMode exportMode; int scriptIndex; int classIndex; NulWriter writer; List<DottedChain> fullyQualifiedNames; int traitIndex; boolean parallel; Trait parent; ConvertData convertData; public TraitConvertTask(Trait trait, Trait parent, ConvertData convertData, boolean makePackages, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List<DottedChain> fullyQualifiedNames, int traitIndex, boolean parallel) { this.trait = trait; this.parent = parent; this.convertData = convertData; this.makePackages = makePackages; this.path = path; this.abc = abc; this.isStatic = isStatic; this.exportMode = exportMode; this.scriptIndex = scriptIndex; this.classIndex = classIndex; this.writer = writer; this.fullyQualifiedNames = fullyQualifiedNames; this.traitIndex = traitIndex; this.parallel = parallel; } @Override public Void call() throws InterruptedException { if (makePackages) { trait.convertPackaged(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); } else { trait.convert(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); } return null; } } public GraphTextWriter toString(Class[] traitTypes, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, GraphTextWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) throws InterruptedException { for (int t = 0; t < traits.size(); t++) { Trait trait = traits.get(t); if (traitTypes != null) { boolean found = false; for (Class c : traitTypes) { if (c.isInstance(trait)) { found = true; break; } } if (!found) { continue; } } if (!trait.isVisible(isStatic, abc)) { continue; } writer.newLine(); int h = t; if (classIndex != -1) { if (!isStatic) { h += abc.class_info.get(classIndex).static_traits.traits.size(); } } if (trait instanceof TraitClass) { writer.startClass(((TraitClass) trait).class_info); } else { writer.startTrait(h); } if (makePackages) { trait.toStringPackaged(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); } else { trait.toString(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); } if (trait instanceof TraitClass) { writer.endClass(); } else { writer.endTrait(); } } return writer; } public void convert(Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, boolean makePackages, int scriptIndex, int classIndex, NulWriter writer, List<DottedChain> fullyQualifiedNames, boolean parallel) throws InterruptedException { if (!parallel || traits.size() < 2) { for (int t = 0; t < traits.size(); t++) { TraitConvertTask task = new TraitConvertTask(traits.get(t), parent, convertData, makePackages, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, t, parallel); task.call(); } } else { ExecutorService executor = Executors.newFixedThreadPool(Configuration.getParallelThreadCount()); List<Future<Void>> futureResults; futureResults = new ArrayList<>(); for (int t = 0; t < traits.size(); t++) { // each convert task needs a separate NulWriter, because they are executed parallel TraitConvertTask task = new TraitConvertTask(traits.get(t), parent, convertData, makePackages, path, abc, isStatic, exportMode, scriptIndex, classIndex, new NulWriter(), fullyQualifiedNames, t, parallel); Future<Void> future = executor.submit(task); futureResults.add(future); } for (int f = 0; f < futureResults.size(); f++) { try { futureResults.get(f).get(); } catch (InterruptedException ex) { executor.shutdownNow(); throw ex; } catch (ExecutionException ex) { Logger.getLogger(Traits.class.getName()).log(Level.SEVERE, "Error during traits converting", ex); } } executor.shutdown(); } } @Override public Traits clone() { try { Traits ret = (Traits) super.clone(); if (traits != null) { ret.traits = new ArrayList<>(traits.size()); for (int i = 0; i < traits.size(); i++) { ret.traits.add(traits.get(i).clone()); } } return ret; } catch (CloneNotSupportedException ex) { throw new RuntimeException(); } } public void getDependencies(String customNs, ABC abc, List<Dependency> dependencies, List<String> uses, DottedChain ignorePackage, List<DottedChain> fullyQualifiedNames) { for (Trait t : traits) { t.getDependencies(customNs, abc, dependencies, uses, ignorePackage, fullyQualifiedNames); } } }