When DCP is published, the DCP is stored to Broker DB and also to custom DB by Storage Extension. To incarnate the above, I implement the program as below.
Furthermore, To confirm whether executing storing to Broker DB and custom DB in same transaction is possible or not I have followed below steps -
First, I have confirmed whether storing DCP to Broker DB is rollbacked or not if some exception occurs in Custom DB. As a result, I know it is possible.
Second, I have confirmed that storing DCP to Custom DB is rollbacked or not if some exception occurs in Broker DB.
When SQLGrammarException occurs in Broker DB(As a result Committing Deployment phase is failed), I have confirmed that storing DCP to Custom DB and Broker DB is not occured. (JPAComponentPresentationDAOImpl class even isn't called because No log is output.)
But I want to confirm whether custom DB is rollbacked or not when super.create(or super.remove) method on JPAComponentPresentationDAOImpl class throws StorageException.
How to cause exception on super.create method ?
@Component("JPAComponentPresentationDAOImpl")
@Scope("prototype")
public class JPAComponentPresentationDAOImpl extends
JPAComponentPresentationDAO implements ComponentPresentationDAO {
public JPAComponentPresentationDAOImpl(String storageId,
EntityManagerFactory entityManagerFactory,
EntityManager entityManager, String storageName) {
super(storageId, entityManagerFactory, entityManager, storageName);
outputLog("JPAComponentPresentationDAOImpl コンストラクタ1");
}
public JPAComponentPresentationDAOImpl(String storageId,
EntityManagerFactory entityManagerFactory, String storageName) {
super(storageId, entityManagerFactory, storageName);
outputLog("JPAComponentPresentationDAOImpl コンストラクタ2");
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
}
// this method is called when a DCP is Published or Re-Published
public void create(ComponentPresentation componentPresentation,
ComponentPresentationTypeEnum type) throws StorageException {
super.create(componentPresentation, type);
if (componentPresentation.getTemplateId() == 176260) {
connectDB(componentPresentation, "create",
componentPresentation.getComponentId());
}
}
public Collection<ComponentPresentation> findAll(int publicationId,
int componentId,
ComponentPresentationTypeEnum componentPresentationType)
throws StorageException {
outputLog("findAll");
return super.findAll(publicationId, componentId,
componentPresentationType);
}
public ComponentPresentation getComponentPresentation(int publicationId,
int componentId, int templateId,
ComponentPresentationTypeEnum componentPresentationType)
throws StorageException {
if (templateId == 176260) {
outputLog("getComponentPresentation");
}
return super.getComponentPresentation(publicationId, componentId,
templateId, componentPresentationType);
// return null;
}
public void remove(ComponentPresentation componentPresentation,
ComponentPresentationTypeEnum type) throws StorageException {
outputLog("Remove1");
super.remove(componentPresentation, type);
}
// this method is called when a DCP is UnPublished
public void remove(int publicationId, int componentId, int templateId,
ComponentPresentationTypeEnum componentPresentationType)
throws StorageException {
super.remove(publicationId, componentId, templateId,
componentPresentationType);
if (templateId == 176260) {
outputLog("Remove2");
connectDB(null, "remove", componentId);
}
}
public void update(ComponentPresentation componentPresentation,
ComponentPresentationTypeEnum componentPresentationType)
throws StorageException {
outputLog("update");
super.update(componentPresentation, componentPresentationType);
}
// start custom code
// output logfile
private static void outputLog(String msg) {
try {
File f = new File("/tmp/Results.log");
BufferedWriter bw = new BufferedWriter(new FileWriter(f, true));
bw.write(msg);
bw.newLine();
bw.close();
} catch (IOException e) {
}
}
// get XML and get NodeValues
private static ArrayList<String> getXml(ComponentPresentation componentPresentation){
// my custom code (to get XML and XMLNodeValues)
}
// connect to DB and executeUpdate
private static void connectDB(ComponentPresentation componentPresentation, String query, int componentId) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rset = null;
ArrayList<String> param = getXml(componentPresentation);
try {
// get driver
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
// connect to sqlserver
String connUrl = getCnnectString();
conn = DriverManager.getConnection(connUrl);
conn.setAutoCommit(false);
// SELECT
if ("create".equals(query)) {
String sql = "SELECT * FROM a WHERE id = ? ;";
ps = conn.prepareStatement(sql);
ps.setInt(1, componentId);
rset = ps.executeQuery();
}
// INSERT or UPDATE
if ("create".equals(query)) {
// INSERT
if (!rset.next()) {
String sql = "INSERT INTO a VALUES (?,?,?,?,?,?,?);";
ps = conn.prepareStatement(sql);
ps.setInt(1, componentId);
for (int i = 0; i < param.size(); i++) {
ps.setNString(i + 2, param.get(i));
}
outputLog("insert");
}
// UPDATE
else {
String sql = "UPDATE a SET name = ?, desc = ?, c_at = ?, c_by = ?, u_at = ?,u_by = ? WHERE id = ? ;";
ps = conn.prepareStatement(sql);
for (int i = 0; i < param.size(); i++) {
ps.setNString(i + 1, param.get(i));
}
ps.setInt(7, componentId);
outputLog("update");
}
}
// DELETE
if ("remove".equals(query)) {
String sql = "DELETE FROM a WHERE id =? ;";
ps = conn.prepareStatement(sql);
ps.setInt(1, componentId);
outputLog("delete");
}
// executeUpdate
ps.executeUpdate();// INSERT, UPDATE, DELETE statment execute
outputLog("Custom DB commit");
conn.commit();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
outputLog("throw SQL Exceptions");
MyJPADAOFactory.setIsFailed(true);
} catch (SQLException e1) {
e1.printStackTrace();
}
outputLog(e.getMessage());
} finally {
if (rset != null) {
try {
rset.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
// set DB info to connect DB
private static String getCnnectString() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
String ConnectString = "";
try {
DocumentBuilder builder = factory.newDocumentBuilder();
File file = new File("/tmp/ConnectDBInfo.xml");
Document doc = (Document) builder.parse(file);
Element root = doc.getDocumentElement();
ConnectString = root.getAttribute("connection");
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return ConnectString;
}
}
@Component("MyJPADAOFactory")
@Scope("singleton")
public class MyJPADAOFactory extends JPADAOFactory implements
ApplicationContextAware {
private static ApplicationContext APPLICATION_CONTEXT;
private static boolean isFailed = false;
public MyJPADAOFactory(String storageId, String dialect) {
super(storageId, dialect);
outputLog("MyJPADAOFactoryコンストラクタ");
}
public MyJPADAOFactory() {
super("", "");
}
public static void setIsFailed(boolean failed) {
isFailed = failed;
}
public void commitTransaction(String transactionId) throws StorageException {
outputLog("commitTransaction開始");
if (isFailed) {
outputLog("ロールバック");
super.rollbackTransaction(transactionId);
throw new StorageException("MyJPADAOFactory : transaction is rollback");
} else {
outputLog("コミット");
super.commitTransaction(transactionId);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
APPLICATION_CONTEXT = applicationContext;
}
public void configureBundle(Configuration storageDAOBundleConfiguration) {
// first set the right value for the private field
// called 'applicationContext'
try {
setPrivateField(this, "applicationContext", APPLICATION_CONTEXT);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
}
// configure the bundle like we normally do
try {
super.configureBundle(storageDAOBundleConfiguration);
} catch (ConfigurationException e) {
e.printStackTrace();
}
}
private static void setPrivateField(final Object fieldOwner,
final String fieldName, final Object value)
throws NoSuchFieldException, IllegalAccessException {
final Field privateField = getPrivateFieldRec(fieldOwner.getClass(),
fieldName);
if (privateField != null) {
final boolean accesible = privateField.isAccessible();
privateField.setAccessible(true);
privateField.set(fieldOwner, value);
privateField.setAccessible(accesible);
}
}
private static Field getPrivateFieldRec(final Class<?> clazz,
final String fieldName) {
for (Field field : clazz.getDeclaredFields()) {
if (fieldName.equals(field.getName())) {
return field;
}
}
final Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null) {
return getPrivateFieldRec(superClazz, fieldName);
}
return null;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
}
private static void outputLog(String msg) {
try {
File f = new File("/tmp/TransactionResult.log");
BufferedWriter bw = new BufferedWriter(new FileWriter(f, true));
bw.write(msg);
bw.newLine();
bw.close();
} catch (IOException e) {
}
}
}
Update
thank you for answering my question. your understanding is not different, but right. I don't well understand when JPAComponentPresentationDAOImpl class is called during comitting deployment phase .
You should have written your create method (in the storage extension) with in the try-catch block so if the super.create generate any exception, the transaction will automatically got rolled back.
is it mean...
Before
public void create(ComponentPresentation componentPresentation,
ComponentPresentationTypeEnum type) throws StorageException {
super.create(componentPresentation, type);
if (componentPresentation.getTemplateId() == 176260) {
connectDB(componentPresentation, "create",
componentPresentation.getComponentId());
}
}
After
public void create(ComponentPresentation componentPresentation,
ComponentPresentationTypeEnum type) throws StorageException {
try{
super.create(componentPresentation, type);
if (componentPresentation.getTemplateId() == 176260) {
connectDB(componentPresentation, "create",
componentPresentation.getComponentId());
}
}
catch(StorageException e)
{
}
}
and I have another problem.
if super.commitTransaction(transactionId) on commitTransaction method (MyJPADAOFactory class) throws exception, I think it's impossible to rollback custom DB, because custom DB is committed before call super.commitTransaction(transactionId).
Can I solve this problem ?