Bonjour,
Quelqu'un pourrait-il m'expliquer comment threader la classe générique de génération de rapports présente dans la FAQ ?
Je n'ai pas envie de faire de bêtises
Merci.
Bonjour,
Quelqu'un pourrait-il m'expliquer comment threader la classe générique de génération de rapports présente dans la FAQ ?
Je n'ai pas envie de faire de bêtises
Merci.
J'ai fais ceci. C'est peut-être pas super mais ça marche bien :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 package utils; import java.io.File; import java.io.OutputStream; import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.eclipse.birt.core.exception.BirtException; import org.eclipse.birt.core.framework.Platform; import org.eclipse.birt.report.engine.api.EngineConfig; import org.eclipse.birt.report.engine.api.EngineException; import org.eclipse.birt.report.engine.api.HTMLRenderOption; import org.eclipse.birt.report.engine.api.IHTMLRenderOption; import org.eclipse.birt.report.engine.api.IRenderOption; import org.eclipse.birt.report.engine.api.IRenderTask; import org.eclipse.birt.report.engine.api.IReportDocument; import org.eclipse.birt.report.engine.api.IReportEngine; import org.eclipse.birt.report.engine.api.IReportEngineFactory; import org.eclipse.birt.report.engine.api.IReportRunnable; import org.eclipse.birt.report.engine.api.IRunTask; import org.eclipse.birt.report.engine.api.RenderOption; /** * Cette classe permet la génération dans n'importe quel format * de n'importe quelle édition. * Il faut d'abord l'instancier, puis l'initialiser et la lancer. * Si nécessaire, cette classe peut être threadée facilement. * * @author BiM * */ public final class Edition { private static Edition m_Instance = null; private IReportEngine engine; private String realPath; private IRenderOption option; private IHTMLRenderOption optionHttp; private String etat; private String chemin; private OutputStream httpResponse; private Map<String, Object> parametres; private String format; private Locale langue; private int encours = 0; /** * Constructeur * Il configure le moteur BIRT de sorte à ce qu'il puisse retrouver * les ressources BIRT mais également les librairies le faisant tourner * Il est alors démarrer avec cette configuration. * @throws BirtException */ private Edition(String realpathParam) throws BirtException { this.realPath = realpathParam; EngineConfig config = new EngineConfig(); config.setResourcePath(new File(realPath, "WEB-INF/reports/ressources").getAbsolutePath()); config.setBIRTHome(new File(realPath, "WEB-INF/ReportEngine").getAbsolutePath());//endroit où se trouvent les librairies du Runtime Platform.startup(config); IReportEngineFactory factory = (IReportEngineFactory) Platform .createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY); engine = factory.createReportEngine(config); option = new RenderOption(); optionHttp = new HTMLRenderOption(); } /** * Instanciation du service * @return l'instance en cours du service * @throws BirtException */ public static Edition getInstance(String realpathParam) throws BirtException { if (m_Instance == null) { m_Instance = new Edition(realpathParam); } return m_Instance; } /** * Initialisation * @param etat nom du rptdesign * @param chemin chemin et nom du fichier de sortie * @param httpResponse le flux de sortie en cas d'utilisation dans une servlet * @param parametres paramètres à passer à l'état * @param format format de sortie (PDF, XLS, DOC, etc.) * @param langue langue de l'édition */ synchronized public void init(String etat, String chemin,OutputStream httpResponse, Map<String, Object> parametres, String format, Locale langue) { if(encours >0){//Inutile de faire le wait s'il n'y a qu'un seul thread try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.etat = etat; this.chemin = chemin; this.httpResponse = httpResponse; this.parametres = parametres; this.format = format; this.langue = langue; encours++; } /** * Lancement de l'état */ synchronized public void run() { try { /* Récupération du rptDesign */ IReportRunnable design = engine.openReportDesign(new File(realPath, "WEB-INF/reports/etats/" + etat + ".rptdesign").getAbsolutePath()); /* Exécution */ IRunTask runTask = engine.createRunTask(design); /* Paramètres */ if(parametres != null){ for (String clef : parametres.keySet()) { runTask.setParameterValue(clef, parametres.get(clef)); } } /* Langue */ runTask.setLocale(langue); runTask.run(chemin+".rptdocument"); /* Récupération du rptDocument */ IReportDocument doc = engine.openReportDocument(chemin+".rptdocument"); /* Rendu */ IRenderTask renderTask = engine.createRenderTask(doc); if(httpResponse == null){ option.setOutputFileName(chemin);//Nom du fichier de sortie renderTask.setRenderOption(option);//Chargement du fichier option.setOutputFormat(format);//Format du fichier de sortie } else{ optionHttp.setOutputStream(httpResponse);//Le flux de sortie vers lequel diriger le fichier générer renderTask.setRenderOption(optionHttp);//Chargement du fichier optionHttp.setOutputFormat(format);//Format du fichier de sortie } renderTask.render();//Création du fichier /envoi du document vers le flux renseigné } catch (EngineException e) { e.printStackTrace(); } finally{ notifyAll(); encours--; } } /** * Permet de détruire le moteur. Cette fonction n'est * jamais utilisée mais pourrait l'être à l'avenir. */ public void destructeur() { engine.destroy(); } }
Le seul truc à peut-être améliorer, c'est lorsque l'utilisateur sur le même navigateur veut générer deux rapports quasi simultanément, l'un étant plus long à construire que l'autre. Etant donné que c'est le même thread, le rapport renvoyé sera le plus rapide à construire. ça c'est normal et ça marche mais j'ai une exception de ce type :
Bien que cela n'entrave pas le fonctionnement du programme, j'aimerais éviter cette erreur mais comment faire ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 ExceptionConverter: ClientAbortException: java.net.SocketException: Software caused connection abort: socket write error at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:358) at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:434) at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:293) at org.apache.catalina.connector.OutputBuffer.writeByte(OutputBuffer.java:399) at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:77) at java.io.FilterOutputStream.write(Unknown Source) at java.io.FilterOutputStream.write(Unknown Source) at java.io.BufferedOutputStream.flushBuffer(Unknown Source) at java.io.BufferedOutputStream.write(Unknown Source) at java.io.BufferedOutputStream.write(Unknown Source) at com.lowagie.text.pdf.OutputStreamCounter.write(Unknown Source) at java.io.ByteArrayOutputStream.writeTo(Unknown Source) at com.lowagie.text.pdf.PdfStream.toPdf(Unknown Source) at com.lowagie.text.pdf.PdfIndirectObject.writeTo(Unknown Source) at com.lowagie.text.pdf.PdfWriter$PdfBody.add(Unknown Source) at com.lowagie.text.pdf.PdfWriter$PdfBody.add(Unknown Source) at com.lowagie.text.pdf.PdfWriter$PdfBody.add(Unknown Source) at com.lowagie.text.pdf.PdfWriter.addToBody(Unknown Source) at com.lowagie.text.pdf.TrueTypeFontUnicode.writeFont(Unknown Source) at com.lowagie.text.pdf.FontDetails.writeFont(Unknown Source) at com.lowagie.text.pdf.PdfWriter.addSharedObjectsToBody(Unknown Source) at com.lowagie.text.pdf.PdfWriter.close(Unknown Source) at com.lowagie.text.pdf.PdfDocument.close(Unknown Source) at com.lowagie.text.Document.close(Unknown Source) at org.eclipse.birt.report.engine.emitter.pdf.PDFPageDevice.close(PDFPageDevice.java:141) at org.eclipse.birt.report.engine.layout.emitter.PageDeviceRender.end(PageDeviceRender.java:158) at org.eclipse.birt.report.engine.emitter.pdf.PDFRender.end(PDFRender.java:121) at org.eclipse.birt.report.engine.layout.emitter.PageEmitter.end(PageEmitter.java:61) at org.eclipse.birt.report.engine.layout.pdf.emitter.PDFLayoutEmitter.end(PDFLayoutEmitter.java:100) at org.eclipse.birt.report.engine.layout.pdf.emitter.WrappedPDFLayoutEmitter.end(WrappedPDFLayoutEmitter.java:69) at org.eclipse.birt.report.engine.layout.pdf.emitter.PDFLayoutEmitterProxy.end(PDFLayoutEmitterProxy.java:218) at org.eclipse.birt.report.engine.emitter.CompositeContentEmitter.end(CompositeContentEmitter.java:64) at org.eclipse.birt.report.engine.api.impl.RenderTask$PageRangeRender.render(RenderTask.java:501) at org.eclipse.birt.report.engine.api.impl.RenderTask.render(RenderTask.java:209) at utils.Edition.run(Edition.java:153) at servlets.BirtServlet.doGet(BirtServlet.java:35) at javax.servlet.http.HttpServlet.service(HttpServlet.java:617) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447) at java.lang.Thread.run(Unknown Source)
Bah... vous avez 2 choix.
1 : sémaphore.
2 : vraie parallélisation
1: en fonction de certains paramètres vous gérez la file d'attente du thread BIRT.
2 : vous avez plusieurs instances de l'engine BIRT et vous achéminez les rapports en fonction de leur disponibilité.
En fait plus simplement, je conseille d'utiliser le mot clef synchronize quand on utilise BIRT. Ca permet d'éviter ce genre de conflit. Une seule génération peut être faite à la fois. Si vous voulez en faire plusieurs, il faut avoir plusieurs moteurs donc plusieurs dossiers Runtime. Parce que les dépendances de BIRT elles mêmes ne peuvent pas gérer les accès concurrentiels.
donc ce que j'ai fais, c'était pas idiot
Ne voulant pas de parallélisation pure mais seulement empecher que les différentes demandes se bouffent entre elles et les enchainer au fûr et à mesure, je pense que je vais rester comme ça.
Ah oui pardon je n'avais pas vu.
Par contre pour éviter l'attente du retour. Tu peux faire un traitement asynchrone. En gros, tu crées une classe avec une file d'attente. Tu ajoutes ton édition à la file d'attente (avec tous ses paramètres (langue, design à utiliser, paramètres, etc.)).
Une fois que tu as ajouté ton édition à la file d'attente, un message est renvoyé à ton client. Et là, tu peux, par exemple, envoyer ton édition par mail quand elle est finie.
Après, il existe de multiples solutions plus ou moins efficaces.
Pas mal comme système, je vais regarder ça.
Merci BiM !
(à très bientôt pour une autre question^^)
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager