/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.vertical.engine.handlers; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.List; import java.util.Map; import org.springframework.stereotype.Component; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import com.enonic.esl.xml.XMLTool; import com.enonic.vertical.engine.VerticalCreateException; import com.enonic.vertical.engine.VerticalEngineLogger; import com.enonic.vertical.engine.VerticalRemoveException; import com.enonic.cms.framework.util.TIntArrayList; import com.enonic.cms.framework.xml.XMLDocument; import com.enonic.cms.framework.xml.XMLDocumentFactory; import com.enonic.cms.core.structure.page.PageEntity; import com.enonic.cms.core.structure.page.PageWindowEntity; @Component("enginePageHandler") public final class PageHandler extends BaseHandler { private static final String PAG_SELECT_KEY = "SELECT pag_lKey FROM tPage "; private static final String PAG_SELECT_KEYS_BY_MENU = "SELECT pag_lKey FROM tPage WHERE pag_lKey IN" + " (SELECT mei_pag_lKey FROM tMenuItem WHERE mei_men_lKey = ?)"; private static final String PAG_WHERE_PAT = "WHERE PAG_PAT_LKEY = ?"; private static final String PAG_REMOVE = "DELETE FROM tPage WHERE pag_lKey IN ("; private static final String PCO_REMOVE = "DELETE FROM tPageConObj WHERE pco_pag_lKey IN ( "; private static final String PCO_REMOVE_WHERE_PAG = "DELETE FROM tPageConObj WHERE pco_pag_lKey = ?"; private static final String PAG_TABLE = "tPage"; private static final String PAG_CREATE = "INSERT INTO tPage (pag_lKey, pag_pat_lKey, pag_sXML) VALUES (?, ?, " + "?"//getSQLConstants().blobString() + ")"; private static final String PCO_CREATE = "INSERT INTO tPageConObj (pco_pag_lKey, pco_cob_lKey, " + "pco_lOrder, pco_ptp_lKey, pco_dteTimestamp) VALUES " + "(?, ?, ?, ?, " + "@currentTimestamp@" + ")"; private static final String PAG_UPDATE = "UPDATE tPage SET " + "pag_pat_lKey = ?, pag_sXML = " + "?" + " WHERE pag_lKey = ?"; private static final String PCO_SELECT_COB = "SELECT pco_cob_lKey FROM tPageConObj"; private static final String PCO_WHERE_PTP = " WHERE pco_ptp_lKey = ?"; private int[] createPage( Document doc ) throws VerticalCreateException { Element docElem = doc.getDocumentElement(); Element[] pageElems; if ( "page".equals( docElem.getTagName() ) ) { pageElems = new Element[]{docElem}; } else { pageElems = XMLTool.getElements( doc.getDocumentElement() ); } Connection con = null; PreparedStatement preparedStmt = null; TIntArrayList newKeys = new TIntArrayList(); try { con = getConnection(); preparedStmt = con.prepareStatement( PAG_CREATE ); for ( Element root : pageElems ) { // key int key; String keyStr = root.getAttribute( "key" ); if ( keyStr == null || keyStr.length() == 0 ) { key = getNextKey( PAG_TABLE ); } else { key = Integer.parseInt( keyStr ); } newKeys.add( key ); preparedStmt.setInt( 1, key ); // attribute: pagetemplatekey String tmp = root.getAttribute( "pagetemplatekey" ); preparedStmt.setInt( 2, Integer.parseInt( tmp ) ); // get the pagedata element and serialize it Element pageDataElement = XMLTool.getElement( root, "pagedata" ); Document pageDataDoc = XMLTool.createDocument(); pageDataDoc.appendChild( pageDataDoc.importNode( pageDataElement, true ) ); byte[] pageDataBytes = XMLTool.documentToBytes( pageDataDoc, "UTF-8" ); preparedStmt.setBytes( 3, pageDataBytes ); // get the sub-elements Map<String, Element> subelems = XMLTool.filterElements( root.getChildNodes() ); // add the page int result = preparedStmt.executeUpdate(); if ( result <= 0 ) { String message = "Failed to create page."; VerticalEngineLogger.errorCreate( message, null ); } // create all pageconobj entries for page Element contentojectsElem = subelems.get( "contentobjects" ); Element[] contentobjectElems = XMLTool.getElements( contentojectsElem ); for ( Element e : contentobjectElems ) { e.setAttribute( "pagekey", Integer.toString( key ) ); } createPageContentObjects( contentojectsElem ); } preparedStmt.close(); preparedStmt = null; } catch ( SQLException sqle ) { String message = "Failed to create page(s) because of database error: %t"; VerticalEngineLogger.errorCreate( message, sqle ); } catch ( NumberFormatException nfe ) { String message = "Failed to parse a key field: %t"; VerticalEngineLogger.errorCreate( message, nfe ); } finally { close( preparedStmt ); } return newKeys.toArray(); } public int createPage( String xmlData ) throws VerticalCreateException { Document doc = XMLTool.domparse( xmlData, "page" ); int[] keys = createPage( doc ); if ( keys == null || keys.length == 0 ) { String message = "Failed to create page , no key returned"; VerticalEngineLogger.errorCreate( message, null ); } return ( keys != null && keys.length > 0 ) ? keys[0] : -1; } private void createPageContentObjects( Element contentobjects ) throws com.enonic.vertical.engine.VerticalCreateException { Node[] contentobject = XMLTool.filterNodes( contentobjects.getChildNodes(), Node.ELEMENT_NODE ); // connection variables Connection con = null; PreparedStatement preparedStmt = null; int pageKey; try { con = getConnection(); preparedStmt = con.prepareStatement( PCO_CREATE ); for ( Node n : contentobject ) { Element co = (Element) n; Map<String, Element> subelems = XMLTool.filterElements( co.getChildNodes() ); // attribute: key (generated in database) String tmp = co.getAttribute( "pagekey" ); pageKey = Integer.parseInt( tmp ); preparedStmt.setInt( 1, pageKey ); // attribute: stylesheet key tmp = co.getAttribute( "conobjkey" ); preparedStmt.setInt( 2, Integer.parseInt( tmp ) ); // attribute: stylesheet key tmp = co.getAttribute( "parameterkey" ); preparedStmt.setInt( 4, Integer.parseInt( tmp ) ); // extract order Element elem = subelems.get( "order" ); int order = Integer.parseInt( XMLTool.getElementText( elem ) ); preparedStmt.setInt( 3, order ); preparedStmt.executeUpdate(); } } catch ( SQLException sqle ) { VerticalEngineLogger.errorCreate( "A database error occured while creating the contentobject page: %t", sqle ); } catch ( NumberFormatException nfe ) { VerticalEngineLogger.errorCreate( "Error parsing the key field: %t", nfe ); } finally { close( preparedStmt ); } } public XMLDocument getPage( int pageKey, boolean complete ) { PageEntity entity = pageDao.findByKey( pageKey ); Document doc = createPagesDocument( entity != null ? Arrays.asList( entity ) : null, complete ); return XMLDocumentFactory.create( doc ); } private Document createPageContentObject( PageEntity entity ) { Document doc = XMLTool.createDocument(); Element root = XMLTool.createRootElement( doc, "contentobjects" ); for ( PageWindowEntity pageWindow : entity.getPageWindows() ) { Element elem = XMLTool.createElement( doc, root, "contentobject" ); elem.setAttribute( "pagekey", String.valueOf( entity.getKey() ) ); elem.setAttribute( "conobjkey", String.valueOf( pageWindow.getPortlet().getKey() ) ); elem.setAttribute( "parameterkey", String.valueOf( pageWindow.getPageTemplateRegion().getKey() ) ); Document contentdata = XMLDocumentFactory.create( pageWindow.getPortlet().getXmlDataAsJDOMDocument() ).getAsDOMDocument(); Node xmldata_root = doc.importNode( contentdata.getDocumentElement(), true ); elem.appendChild( xmldata_root ); XMLTool.createElement( doc, elem, "order", String.valueOf( pageWindow.getOrder() ) ); XMLTool.createElement( doc, elem, "name", pageWindow.getPortlet().getName() ); XMLTool.createElement( doc, elem, "separator", pageWindow.getPageTemplateRegion().getSeparator() ); elem = XMLTool.createElement( doc, elem, "parametername", pageWindow.getPageTemplateRegion().getName() ); elem.setAttribute( "multiple", String.valueOf( pageWindow.getPageTemplateRegion().isMultiple() ) ); elem.setAttribute( "override", String.valueOf( pageWindow.getPageTemplateRegion().isOverride() ) ); } return doc; } private Document createPagesDocument( List<PageEntity> entities, boolean complete ) { Document doc = XMLTool.createDocument(); Element root = XMLTool.createRootElement( doc, "pages" ); if ( entities != null ) { for ( PageEntity page : entities ) { Element elem = XMLTool.createElement( doc, root, "page" ); elem.setAttribute( "key", String.valueOf( page.getKey() ) ); elem.setAttribute( "pagetemplatekey", String.valueOf( page.getTemplate().getKey() ) ); org.jdom.Document pageXmlDataAsJdomDoc = page.getXmlDataAsDocument(); if ( pageXmlDataAsJdomDoc != null ) { Document pageDataDocument = XMLDocumentFactory.create( pageXmlDataAsJdomDoc ).getAsDOMDocument(); elem.appendChild( doc.importNode( pageDataDocument.getDocumentElement(), true ) ); } else { XMLTool.createElement( doc, elem, "pagedata" ); } if ( complete ) { Document contentobj = createPageContentObject( page ); Node contentobjects_root = doc.importNode( contentobj.getDocumentElement(), true ); elem.appendChild( contentobjects_root ); } } } return doc; } public int[] getPageKeysByMenu( Connection _con, int menuKey ) { Connection con = null; PreparedStatement prepStmt = null; ResultSet resultSet = null; TIntArrayList pageKeys = new TIntArrayList(); try { if ( _con == null ) { con = getConnection(); } else { con = _con; } prepStmt = con.prepareStatement( PAG_SELECT_KEYS_BY_MENU ); prepStmt.setInt( 1, menuKey ); resultSet = prepStmt.executeQuery(); while ( resultSet.next() ) { pageKeys.add( resultSet.getInt( "pag_lKey" ) ); } } catch ( SQLException sqle ) { String message = "Failed to get page keys by menu: %"; VerticalEngineLogger.error( message, sqle ); } finally { close( resultSet ); close( prepStmt ); if ( _con == null ) { } } return pageKeys.toArray(); } public int[] getPageKeysByPageTemplateKey( int pageTemplateKey ) { Connection con = null; PreparedStatement preparedStmt = null; ResultSet resultSet = null; TIntArrayList pageKeys = new TIntArrayList(); try { StringBuffer sql = new StringBuffer( PAG_SELECT_KEY ); sql.append( PAG_WHERE_PAT ); con = getConnection(); preparedStmt = con.prepareStatement( sql.toString() ); preparedStmt.setInt( 1, pageTemplateKey ); resultSet = preparedStmt.executeQuery(); while ( resultSet.next() ) { pageKeys.add( resultSet.getInt( "pag_lKey" ) ); } } catch ( SQLException se ) { String message = "Failed to get page keys by page template key: %t"; VerticalEngineLogger.error( message, se ); } finally { close( resultSet ); close( preparedStmt ); } return pageKeys.toArray(); } public int[] getContentObjectKeys( int[] pageTemplateParameterKeys ) { Connection con = null; PreparedStatement preparedStmt = null; ResultSet resultSet = null; TIntArrayList contentObjectKeys = new TIntArrayList(); try { StringBuffer sql = new StringBuffer( PCO_SELECT_COB ); sql.append( PCO_WHERE_PTP ); con = getConnection(); preparedStmt = con.prepareStatement( sql.toString() ); for ( int pageTemplateParameterKey : pageTemplateParameterKeys ) { preparedStmt.setInt( 1, pageTemplateParameterKey ); resultSet = preparedStmt.executeQuery(); while ( resultSet.next() ) { contentObjectKeys.add( resultSet.getInt( 1 ) ); } } } catch ( SQLException se ) { String message = "Failed to get page keys by page template key: %t"; VerticalEngineLogger.error( message ); } finally { close( resultSet ); close( preparedStmt ); } return contentObjectKeys.toArray(); } public void removePage( int pageKey ) throws VerticalRemoveException { removePages( null, new int[]{pageKey} ); } public void removePageContentObjects( int pageKey, int[] contentObjectKeys ) throws VerticalRemoveException { Connection con = null; PreparedStatement preparedStmt = null; StringBuffer sql = new StringBuffer( PCO_REMOVE_WHERE_PAG ); if ( contentObjectKeys != null && contentObjectKeys.length > 0 ) { sql.append( " AND pco_cob_lKey = ?" ); } try { con = getConnection(); preparedStmt = con.prepareStatement( sql.toString() ); preparedStmt.setInt( 1, pageKey ); if ( contentObjectKeys != null && contentObjectKeys.length > 0 ) { for ( int contentObjectKey : contentObjectKeys ) { preparedStmt.setInt( 2, contentObjectKey ); preparedStmt.executeUpdate(); } } else { preparedStmt.executeUpdate(); } } catch ( SQLException sqle ) { String message = "Failed to remove page content objects because of database error: %t"; VerticalEngineLogger.errorRemove( message, sqle ); } finally { close( preparedStmt ); } } private void removePageContentObjects( Connection _con, int[] pageKeys ) { if ( pageKeys != null && pageKeys.length > 0 ) { Connection con = null; PreparedStatement preparedStmt = null; String sql = PCO_REMOVE; try { if ( _con == null ) { con = getConnection(); } else { con = _con; } for ( int pageKey : pageKeys ) { sql = sql + "?, "; } sql = sql.substring( 0, sql.length() - 2 ) + ")"; preparedStmt = con.prepareStatement( sql ); for ( int i = 0; i < pageKeys.length; i++ ) { preparedStmt.setInt( i + 1, pageKeys[i] ); } preparedStmt.executeUpdate(); } catch ( SQLException sqle ) { String message = "Failed to remove content objects from pages: %t"; VerticalEngineLogger.errorRemove( message, sqle ); } finally { close( preparedStmt ); if ( _con == null ) { } } } } public void removePages( Connection _con, int[] pageKeys ) { if ( pageKeys != null && pageKeys.length > 0 ) { removePageContentObjects( _con, pageKeys ); Connection con = null; PreparedStatement preparedStmt = null; String sql = PAG_REMOVE; try { if ( _con == null ) { con = getConnection(); } else { con = _con; } for ( int pageKey : pageKeys ) { sql = sql + "?, "; } sql = sql.substring( 0, sql.length() - 2 ) + ")"; preparedStmt = con.prepareStatement( sql ); for ( int i = 0; i < pageKeys.length; i++ ) { preparedStmt.setInt( i + 1, pageKeys[i] ); } preparedStmt.executeUpdate(); } catch ( SQLException sqle ) { String message = "Failed to remove pages: %t"; VerticalEngineLogger.errorRemove( message, sqle ); } finally { close( preparedStmt ); if ( _con == null ) { } } } } public void updatePage( String xmlData ) { Document doc = XMLTool.domparse( xmlData, "page" ); updatePage( doc ); } private void updatePage( Document doc ) { Element docElem = doc.getDocumentElement(); Element[] pageElems; if ( "page".equals( docElem.getTagName() ) ) { pageElems = new Element[]{docElem}; } else { pageElems = XMLTool.getElements( doc.getDocumentElement() ); } Connection con = null; PreparedStatement preparedStmt = null; try { con = getConnection(); preparedStmt = con.prepareStatement( PAG_UPDATE ); for ( Element root : pageElems ) { Map<String, Element> subelems = XMLTool.filterElements( root.getChildNodes() ); // attribute: key String tmp = root.getAttribute( "key" ); int pageKey = Integer.parseInt( tmp ); preparedStmt.setInt( 3, pageKey ); // get the pagedata element and serialize it Element pageDataElement = XMLTool.getElement( root, "pagedata" ); Document pageDataDoc = XMLTool.createDocument(); pageDataDoc.appendChild( pageDataDoc.importNode( pageDataElement, true ) ); byte[] pageDataBytes = XMLTool.documentToBytes( pageDataDoc, "UTF-8" ); preparedStmt.setBytes( 2, pageDataBytes ); // attribute: pagetemplatekey key tmp = root.getAttribute( "pagetemplatekey" ); preparedStmt.setInt( 1, Integer.parseInt( tmp ) ); // add the stylesheet int result = preparedStmt.executeUpdate(); if ( result == 0 ) { String message = "Unable to update page: %t"; VerticalEngineLogger.errorUpdate( message, null ); } // update all pageconobj entries for page try { // delete old contentobjects removePageContentObjects( con, new int[]{pageKey} ); Element contentojects = subelems.get( "contentobjects" ); createPageContentObjects( contentojects ); } catch ( VerticalCreateException vce ) { String message = "Could not create content objects."; VerticalEngineLogger.errorUpdate( message, vce ); } } } catch ( SQLException sqle ) { String message = "Failed to update page: %t"; VerticalEngineLogger.errorUpdate( message, sqle ); } catch ( NumberFormatException nfe ) { String message = "Unable to parse page key: %t"; VerticalEngineLogger.errorUpdate( message, nfe ); } finally { close( preparedStmt ); } } }