1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.efaps.db.store;
22
23 import java.io.ByteArrayOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.sql.Connection;
28 import java.sql.PreparedStatement;
29 import java.sql.ResultSet;
30 import java.sql.SQLException;
31 import java.util.Calendar;
32
33 import javax.jcr.AccessDeniedException;
34 import javax.jcr.Binary;
35 import javax.jcr.InvalidItemStateException;
36 import javax.jcr.ItemExistsException;
37 import javax.jcr.LoginException;
38 import javax.jcr.NoSuchWorkspaceException;
39 import javax.jcr.Node;
40 import javax.jcr.Property;
41 import javax.jcr.ReferentialIntegrityException;
42 import javax.jcr.Repository;
43 import javax.jcr.RepositoryException;
44 import javax.jcr.Session;
45 import javax.jcr.SimpleCredentials;
46 import javax.jcr.lock.LockException;
47 import javax.jcr.nodetype.ConstraintViolationException;
48 import javax.jcr.nodetype.NoSuchNodeTypeException;
49 import javax.jcr.nodetype.NodeType;
50 import javax.jcr.version.VersionException;
51 import javax.naming.InitialContext;
52 import javax.naming.NamingException;
53 import javax.transaction.xa.XAException;
54 import javax.transaction.xa.Xid;
55
56 import org.efaps.db.Context;
57 import org.efaps.db.Instance;
58 import org.efaps.db.transaction.ConnectionResource;
59 import org.efaps.db.wrapper.SQLSelect;
60 import org.efaps.util.EFapsException;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64
65
66
67
68
69
70 public class JCRStoreResource
71 extends AbstractStoreResource
72 {
73
74
75
76 public static final String TABLENAME_STORE = "T_CMGENSTOREJCR";
77
78
79
80
81 public static final String COLNAME_IDENTIFIER = "IDENTIFIER";
82
83
84
85
86 private static final Logger LOG = LoggerFactory.getLogger(JCRStoreResource.class);
87
88
89
90
91
92 private static final String PROPERTY_WORKSPACENAME = "JCRWorkSpaceName";
93
94
95
96
97 private static final String PROPERTY_ENABLEDELETION = "JCREnableDeletion";
98
99
100
101
102 private static final String PROPERTY_USERNAME = "JCRUserName";
103
104
105
106
107 private static final String PROPERTY_PASSWORD = "JCRPassword";
108
109
110
111
112
113 private Repository repository;
114
115
116
117
118 private String identifier;
119
120
121
122
123 private Session session;
124
125
126
127
128 @Override
129 public void initialize(final Instance _instance,
130 final Store _store)
131 throws EFapsException
132 {
133 super.initialize(_instance, _store);
134 try {
135 final InitialContext ctx = new InitialContext();
136 this.repository = (Repository) ctx.lookup(getStore().getProperty(Store.PROPERTY_JNDINAME));
137 if (JCRStoreResource.LOG.isDebugEnabled()) {
138 final String name = this.repository.getDescriptor(Repository.REP_NAME_DESC);
139 JCRStoreResource.LOG.debug("Successfully retrieved '%s' repository from JNDI", new Object[]{ name });
140 }
141 String username = getProperties().get(JCRStoreResource.PROPERTY_USERNAME);
142 if (username == null) {
143 username = Context.getThreadContext().getPerson().getName();
144 }
145 String passwd = getProperties().get(JCRStoreResource.PROPERTY_PASSWORD);
146 if (passwd == null) {
147 passwd = "efaps";
148 }
149 this.session = this.repository.login(new SimpleCredentials(username, passwd.toCharArray()),
150 getProperties().get(JCRStoreResource.PROPERTY_WORKSPACENAME));
151 } catch (final NamingException e) {
152 throw new EFapsException(JCRStoreResource.class, "initialize.NamingException", e);
153 } catch (final LoginException e) {
154 throw new EFapsException(JCRStoreResource.class, "initialize.LoginException", e);
155 } catch (final NoSuchWorkspaceException e) {
156 throw new EFapsException(JCRStoreResource.class, "initialize.NoSuchWorkspaceException", e);
157 } catch (final RepositoryException e) {
158 throw new EFapsException(JCRStoreResource.class, "initialize.RepositoryException", e);
159 }
160 }
161
162
163
164
165 @Override
166 protected int add2Select(final SQLSelect _select)
167 {
168 _select.column(2, "ID").column(2, JCRStoreResource.COLNAME_IDENTIFIER)
169 .leftJoin(JCRStoreResource.TABLENAME_STORE, 2, "ID", 0, "ID");
170 return 1;
171 }
172
173
174
175
176 @Override
177 protected void getAdditionalInfo(final ResultSet _rs)
178 throws SQLException
179 {
180 final String identiferTmp = _rs.getString(6);
181 if (identiferTmp != null && !identiferTmp.isEmpty()) {
182 this.identifier = identiferTmp.trim();
183 }
184 }
185
186
187
188
189 @Override
190 protected void insertDefaults()
191 throws EFapsException
192 {
193 super.insertDefaults();
194 if (!getExist()[1] && getGeneralID() != null) {
195 try {
196 final ConnectionResource res = Context.getThreadContext().getConnectionResource();
197 final Connection con = res.getConnection();
198 Context.getDbType().newInsert(JCRStoreResource.TABLENAME_STORE, "ID", false)
199 .column("ID", getGeneralID())
200 .column(JCRStoreResource.COLNAME_IDENTIFIER, "NEW")
201 .execute(con);
202 res.commit();
203 } catch (final SQLException e) {
204 throw new EFapsException(JCRStoreResource.class, "insertDefaults", e);
205 }
206 }
207 }
208
209
210
211
212 @Override
213 public long write(final InputStream _in,
214 final long _size,
215 final String _fileName)
216 throws EFapsException
217 {
218 final JCRBinary bin = new JCRBinary(_in);
219 long size = _size;
220 try {
221 final Node rootNode = this.session.getRootNode();
222 final Node fileNode = rootNode.addNode(getInstance().getOid(), NodeType.NT_FILE);
223 final Node resNode = fileNode.addNode(Property.JCR_CONTENT, NodeType.NT_RESOURCE);
224 resNode.setProperty(Property.JCR_DATA, bin);
225 resNode.setProperty(Property.JCR_LAST_MODIFIED, Calendar.getInstance());
226 resNode.setProperty(Property.JCR_LAST_MODIFIED_BY, Context.getThreadContext().getPerson().getName());
227 setIdentifer(fileNode.getIdentifier());
228
229 if (size < 0) {
230 final byte[] buffer = new byte[1024];
231 int length = 1;
232 size = 0;
233 final OutputStream out = new ByteArrayOutputStream();
234 while (length > 0) {
235 length = _in.read(buffer);
236 if (length > 0) {
237 out.write(buffer, 0, length);
238 size += length;
239 }
240 }
241 }
242 } catch (final RepositoryException e) {
243 throw new EFapsException(JCRStoreResource.class, "write.RepositoryException", e);
244 } catch (final IOException e) {
245 throw new EFapsException(JCRStoreResource.class, "write.IOException", e);
246 }
247 setFileInfo(_fileName, size);
248 return size;
249 }
250
251
252
253
254
255
256 protected void setIdentifer(final String _identifier)
257 throws EFapsException
258 {
259 if (!_identifier.equals(this.identifier)) {
260
261 ConnectionResource res = null;
262 try {
263 res = Context.getThreadContext().getConnectionResource();
264
265 final StringBuffer cmd = new StringBuffer().append("update ")
266 .append(JCRStoreResource.TABLENAME_STORE).append(" set ")
267 .append(JCRStoreResource.COLNAME_IDENTIFIER).append("=? ")
268 .append("where ID =").append(getGeneralID());
269
270 final PreparedStatement stmt = res.getConnection().prepareStatement(cmd.toString());
271 try {
272 stmt.setString(1, _identifier);
273 stmt.execute();
274 } finally {
275 stmt.close();
276 }
277 res.commit();
278 this.identifier = _identifier;
279 } catch (final EFapsException e) {
280 res.abort();
281 throw e;
282 } catch (final SQLException e) {
283 res.abort();
284 throw new EFapsException(JDBCStoreResource.class, "write.SQLException", e);
285 }
286 }
287 }
288
289
290
291
292
293 @Override
294 protected Compress getCompress()
295 {
296 return Compress.NONE;
297 }
298
299
300
301
302 @Override
303 public InputStream read()
304 throws EFapsException
305 {
306 InputStream input = null;
307 try {
308 final Node fileNode = this.session.getNodeByIdentifier(this.identifier);
309 final Node resNode = fileNode.getNode(Property.JCR_CONTENT);
310 final Property data = resNode.getProperty(Property.JCR_DATA);
311 final Binary bin = data.getBinary();
312 input = new JCRStoreResourceInputStream(this, bin);
313 } catch (final RepositoryException e) {
314 throw new EFapsException(JCRStoreResource.class, "read.RepositoryException", e);
315 } catch (final IOException e) {
316 throw new EFapsException(JCRStoreResource.class, "read.IOException", e);
317 }
318 return input;
319 }
320
321
322
323
324 @Override
325 public void delete()
326 throws EFapsException
327 {
328
329 if (getExist()[0] && getExist()[1]
330 && "TRUE".equalsIgnoreCase(getProperties().get(JCRStoreResource.PROPERTY_ENABLEDELETION))) {
331 try {
332 final Node fileNode = this.session.getNodeByIdentifier(this.identifier);
333 fileNode.remove();
334 } catch (final RepositoryException e) {
335 throw new EFapsException(JCRStoreResource.class, "delete.RepositoryException", e);
336 }
337 }
338 }
339
340
341
342
343
344
345
346
347
348
349
350
351
352 @Override
353 public void commit(final Xid _xid,
354 final boolean _onePhase)
355 throws XAException
356 {
357 try {
358 if (this.session.hasPendingChanges()) {
359 this.session.save();
360 }
361 this.session.logout();
362 } catch (final AccessDeniedException e) {
363 throw new XAException("AccessDeniedException");
364 } catch (final ItemExistsException e) {
365 throw new XAException("ItemExistsException");
366 } catch (final ReferentialIntegrityException e) {
367 throw new XAException("ReferentialIntegrityException");
368 } catch (final ConstraintViolationException e) {
369 throw new XAException("AccessDeniedException");
370 } catch (final InvalidItemStateException e) {
371 throw new XAException("InvalidItemStateException");
372 } catch (final VersionException e) {
373 throw new XAException("VersionException");
374 } catch (final LockException e) {
375 throw new XAException(XAException.XA_RBDEADLOCK);
376 } catch (final NoSuchNodeTypeException e) {
377 throw new XAException("NoSuchNodeTypeException");
378 } catch (final RepositoryException e) {
379 throw new XAException("RepositoryException");
380 }
381 }
382
383
384
385
386
387
388
389
390 @Override
391 public void forget(final Xid _xid)
392 {
393 if (JCRStoreResource.LOG.isDebugEnabled()) {
394 JCRStoreResource.LOG.debug("forget (xid = " + _xid + ")");
395 }
396 }
397
398
399
400
401
402
403
404 public int getTransactionTimeout()
405 {
406 if (JCRStoreResource.LOG.isDebugEnabled()) {
407 JCRStoreResource.LOG.debug("getTransactionTimeout");
408 }
409 return 0;
410 }
411
412
413
414
415
416
417
418
419 public int prepare(final Xid _xid)
420 {
421 if (JCRStoreResource.LOG.isDebugEnabled()) {
422 JCRStoreResource.LOG.debug("prepare (xid=" + _xid + ")");
423 }
424 return 0;
425 }
426
427
428
429
430
431
432
433 public Xid[] recover(final int _flag)
434 {
435 if (JCRStoreResource.LOG.isDebugEnabled()) {
436 JCRStoreResource.LOG.debug("recover (flag = " + _flag + ")");
437 }
438 return null;
439 }
440
441
442
443
444
445
446
447
448
449
450 @Override
451 public void rollback(final Xid _xid)
452 throws XAException
453 {
454 this.session.logout();
455 }
456
457
458
459
460
461
462
463 public boolean setTransactionTimeout(final int _seconds)
464 {
465 if (JCRStoreResource.LOG.isDebugEnabled()) {
466 JCRStoreResource.LOG.debug("setTransactionTimeout (seconds = " + _seconds + ")");
467 }
468 return true;
469 }
470
471
472
473
474
475 private static class JCRBinary
476 implements Binary
477 {
478
479
480
481 private InputStream stream;
482
483
484
485
486 public JCRBinary(final InputStream _in)
487 {
488 this.stream = _in;
489 }
490
491
492
493
494
495
496
497
498
499
500
501
502
503 @Override
504 public InputStream getStream()
505 throws RepositoryException
506 {
507 return this.stream;
508 }
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529 @Override
530 public int read(final byte[] _b,
531 final long _position)
532 throws IOException, RepositoryException
533 {
534 return this.stream.read(_b);
535 }
536
537
538
539
540
541
542
543
544
545
546
547 @Override
548 public long getSize()
549 throws RepositoryException
550 {
551 return 0;
552 }
553
554
555
556
557
558
559
560 @Override
561 public void dispose()
562 {
563 try {
564 this.stream.close();
565 } catch (final IOException e) {
566 JCRStoreResource.LOG.error("Error on disposal of inpustream.", e);
567 }
568 }
569 }
570
571
572
573
574 private class JCRStoreResourceInputStream
575 extends StoreResourceInputStream
576 {
577
578
579
580
581
582
583
584 protected JCRStoreResourceInputStream(final AbstractStoreResource _store,
585 final Binary _bin)
586 throws IOException, RepositoryException
587 {
588 super(_store, _bin.getStream());
589 }
590 }
591 }