Before proceding to any change to your application, please make sure that you have a valid and runnable back-up of your application and data. We also recommend to conduct these operations on a dedicated test server that replicates the environment of your live application and data.
JCR storage changes
Some important modifications were made to the JCR storage format. Immediately after upgrading the CMS, the custom_nodetypes file, located at <JCR repository path>/repository/nodetypes/custom_nodetypes.xml, must be deleted. A new valid file will be created when the server is restarted.
Note that the data migration is NOT reversible. You won't be able to rollback to a previous version of Ametys.
I18n catalogues update
Overriden i18n keys
If you have overridden some i18n catalogues in WEB-INF/i18n/plugins, you have to change the location of the files.
For a plugin named "foo", you had the catalogue at WEB-INF/i18n/plugins/foo.xml.
You now have to put it at WEB-INF/i18n/plugins/foo/messages.xml
Please note that, as of 3.4, you may override only a few keys and not all the catalogue.
Location changed
Some i18n keys of the ribbon have been moved from Web to CMS.
In yours WEB-INF/params/ribbon-*.xml files remplace the following keys:
The version of jackrabbit must be updated (e.g. from 2.2.7 to 2.4.2).
The "rev" attribute of the jackrabbit dependency must be "2.4.2-ametys".
If the application's dependencies are managed using ivy, the ivy.xml file has to be updated accordingly.
Runtime.xml changes
View selector
A new "ViewSelector" extension point has appeared. If the application uses the Web module, the following line has to be added to the "WEB-INF/param/runtime.xml" file, in the "extensions" section:
Oops !
Copy to clipboard failed. Open the code and copy it manually.
In some project, the sitemapInputData of the web plugin is overridden. To know if it is the case in the project, you can look at the file "WEB-INF/param/inpudata.xml". If in this file the input-data "org.ametys.web.inputdata.SitemapInputData" is not present, you must disable it. To do this, you must add this line in "WEB-INF/param/runtime.xml", in the "plugins" and "exclude" section :
Oops !
Copy to clipboard failed. Open the code and copy it manually.
<feature>web/inputdata.sitemap</feature>
<feature>web/inputdata.sitemap</feature>
<feature>web/inputdata.sitemap</feature>
RequestAttributeWorkspaceSelector
If the "WEB-INF/param/runtime.xml" file contains the extension org.ametys.web.repository.RequestAttributeWorkspaceSelector, it should be replaced by org.ametys.cms.repository.RequestAttributeWorkspaceSelector
Content type class modification
When using the Web module, the ContentType implementation class has changed.
All occurrences of "org.ametys.cms.contenttype.DefaultContentType" in plugin.xml files should be replaced with "org.ametys.web.contenttype.WebContentType".
Package changing
org.ametys.web.workflow.ValidationStepFunction has moved to org.ametys.cms.workflow.ValidationStepFunction.
All occurences of org.ametys.web.workflow.ValidationStepFunction in the WEB-INF/params/workflow*.xml files should be replaced:
workflow.xml
workflow-blog.xml
workflow-newsletter.xml
...
FAQ data (1.0 to 1.1)
FAQ answers are now rich text. You have to execute the following script (in the repository console) to migrate your data :
Oops !
Copy to clipboard failed. Open the code and copy it manually.
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultWebContent)[@ametys-internal:contentType = 'org.ametys.plugins.faq.Content.faq']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var faqContent = nodes.next();
if (faqContent.hasNode("ametys:questions"))
{
var questions = faqContent.getNode("ametys:questions").getNodes();
while (questions.hasNext())
{
var question = questions.next();
if (question.hasProperty("ametys:answer"))
{
var prop = question.getProperty("ametys:answer");
var currentValue = question.getProperty("ametys:answer").getString();
prop.remove();
var answer = question.addNode("ametys:answer", "ametys:richText");
var content = '<?xml version="1.0" encoding="UTF-8"?><article xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:html="http://www.w3.org/1999/xhtml" version="5.0"><para>'
+ currentValue.replaceAll("&", '&').replace("<", '<').replace(">", '>').replace("\n", '<phrase role="linebreak"/>')
+ '</para></article>';
answer.setProperty("jcr:data", org.apache.commons.io.IOUtils.toInputStream(content));
answer.setProperty("jcr:mimeType", "text/xml");
}
}
}
count++;
}
session.save();
print (count + " FAQ converted");
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultWebContent)[@ametys-internal:contentType = 'org.ametys.plugins.faq.Content.faq']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var faqContent = nodes.next();
if (faqContent.hasNode("ametys:questions"))
{
var questions = faqContent.getNode("ametys:questions").getNodes();
while (questions.hasNext())
{
var question = questions.next();
if (question.hasProperty("ametys:answer"))
{
var prop = question.getProperty("ametys:answer");
var currentValue = question.getProperty("ametys:answer").getString();
prop.remove();
var answer = question.addNode("ametys:answer", "ametys:richText");
var content = '<?xml version="1.0" encoding="UTF-8"?><article xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:html="http://www.w3.org/1999/xhtml" version="5.0"><para>'
+ currentValue.replaceAll("&", '&').replace("<", '<').replace(">", '>').replace("\n", '<phrase role="linebreak"/>')
+ '</para></article>';
answer.setProperty("jcr:data", org.apache.commons.io.IOUtils.toInputStream(content));
answer.setProperty("jcr:mimeType", "text/xml");
}
}
}
count++;
}
session.save();
print (count + " FAQ converted");
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:defaultWebContent)[@ametys-internal:contentType = 'org.ametys.plugins.faq.Content.faq']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var faqContent = nodes.next();
if (faqContent.hasNode("ametys:questions"))
{
var questions = faqContent.getNode("ametys:questions").getNodes();
while (questions.hasNext())
{
var question = questions.next();
if (question.hasProperty("ametys:answer"))
{
var prop = question.getProperty("ametys:answer");
var currentValue = question.getProperty("ametys:answer").getString();
prop.remove();
var answer = question.addNode("ametys:answer", "ametys:richText");
var content = '<?xml version="1.0" encoding="UTF-8"?><article xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:html="http://www.w3.org/1999/xhtml" version="5.0"><para>'
+ currentValue.replaceAll("&", '&').replace("<", '<').replace(">", '>').replace("\n", '<phrase role="linebreak"/>')
+ '</para></article>';
answer.setProperty("jcr:data", org.apache.commons.io.IOUtils.toInputStream(content));
answer.setProperty("jcr:mimeType", "text/xml");
}
}
}
count++;
}
session.save();
print (count + " FAQ converted");
All FAQ contents needs to be revalidated using the search tool.
Service migration
To cut down the service count, several has been merged or regrouped. Below are migration scripts that have to be run in the Console tab in the repository workspace.
Front search service
"Front search criteria" service is now part of the "front search" service. There is a new parameter to specify the display mode, and optionally redirect the search to a specified page. To migrate existing services, execute the following script:
Oops !
Copy to clipboard failed. Open the code and copy it manually.
var frontXsltMap = {
'pages/services/search-criteria/search-criteria.xsl': 'pages/services/search/search.xsl',
'pages/services/search-criteria/search-criteria_3.3.xsl': 'pages/services/search/search_3.3.xsl'
}
var qm = session.getWorkspace().getQueryManager();
var migrated = 0;
// Criteria for front search: change into front search, criteria-only mode.
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.CriteriaForFrontSearchService']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
var message = 'Migrated front criteria service: ' + node.getPath();
var currentServiceXSLT = paramsNode.getProperty('ametys:xslt').getString();
node.setProperty('ametys-internal:service', 'org.ametys.web.service.FrontSearchService');
paramsNode.setProperty('ametys:search-mode', 'criteria-only');
if (frontXsltMap[currentServiceXSLT] != null)
{
paramsNode.setProperty('ametys:xslt', frontXsltMap[currentServiceXSLT]);
message += ', new xslt is: ' + frontXsltMap[currentServiceXSLT];
}
println(message);
migrated++;
}
// Front search: change the search mode.
query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.FrontSearchService']/ametys:service_parameters[@ametys:on-same-page]", javax.jcr.query.Query.XPATH);
nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var onSamePage = node.getProperty('ametys:on-same-page').getBoolean();
var mode = onSamePage ? 'criteria-and-results' : 'criteria-or-results';
node.setProperty('ametys:search-mode', mode);
println('Migrated front search service parameters.');
migrated++;
}
println('=> ' + migrated + ' FO search service(s) have been migrated.');
session.save();
var frontXsltMap = {
'pages/services/search-criteria/search-criteria.xsl': 'pages/services/search/search.xsl',
'pages/services/search-criteria/search-criteria_3.3.xsl': 'pages/services/search/search_3.3.xsl'
}
var qm = session.getWorkspace().getQueryManager();
var migrated = 0;
// Criteria for front search: change into front search, criteria-only mode.
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.CriteriaForFrontSearchService']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
var message = 'Migrated front criteria service: ' + node.getPath();
var currentServiceXSLT = paramsNode.getProperty('ametys:xslt').getString();
node.setProperty('ametys-internal:service', 'org.ametys.web.service.FrontSearchService');
paramsNode.setProperty('ametys:search-mode', 'criteria-only');
if (frontXsltMap[currentServiceXSLT] != null)
{
paramsNode.setProperty('ametys:xslt', frontXsltMap[currentServiceXSLT]);
message += ', new xslt is: ' + frontXsltMap[currentServiceXSLT];
}
println(message);
migrated++;
}
// Front search: change the search mode.
query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.FrontSearchService']/ametys:service_parameters[@ametys:on-same-page]", javax.jcr.query.Query.XPATH);
nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var onSamePage = node.getProperty('ametys:on-same-page').getBoolean();
var mode = onSamePage ? 'criteria-and-results' : 'criteria-or-results';
node.setProperty('ametys:search-mode', mode);
println('Migrated front search service parameters.');
migrated++;
}
println('=> ' + migrated + ' FO search service(s) have been migrated.');
session.save();
var frontXsltMap = {
'pages/services/search-criteria/search-criteria.xsl': 'pages/services/search/search.xsl',
'pages/services/search-criteria/search-criteria_3.3.xsl': 'pages/services/search/search_3.3.xsl'
}
var qm = session.getWorkspace().getQueryManager();
var migrated = 0;
// Criteria for front search: change into front search, criteria-only mode.
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.CriteriaForFrontSearchService']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
var message = 'Migrated front criteria service: ' + node.getPath();
var currentServiceXSLT = paramsNode.getProperty('ametys:xslt').getString();
node.setProperty('ametys-internal:service', 'org.ametys.web.service.FrontSearchService');
paramsNode.setProperty('ametys:search-mode', 'criteria-only');
if (frontXsltMap[currentServiceXSLT] != null)
{
paramsNode.setProperty('ametys:xslt', frontXsltMap[currentServiceXSLT]);
message += ', new xslt is: ' + frontXsltMap[currentServiceXSLT];
}
println(message);
migrated++;
}
// Front search: change the search mode.
query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.FrontSearchService']/ametys:service_parameters[@ametys:on-same-page]", javax.jcr.query.Query.XPATH);
nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var onSamePage = node.getProperty('ametys:on-same-page').getBoolean();
var mode = onSamePage ? 'criteria-and-results' : 'criteria-or-results';
node.setProperty('ametys:search-mode', mode);
println('Migrated front search service parameters.');
migrated++;
}
println('=> ' + migrated + ' FO search service(s) have been migrated.');
session.save();
Tag cloud service
The tag cloud and word cloud service parameters have been reworked. On a tag cloud, the "order by" parameter has been removed. On a word cloud, the "score" order has been changed to "input order". To migrate existing instances, run the following script:
Oops !
Copy to clipboard failed. Open the code and copy it manually.
var qm = session.getWorkspace().getQueryManager();
var migrated = 0;
// Tag cloud on tags.
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.plugins.tagcloud.services.Tags']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
if (paramsNode.hasProperty('ametys:order-by'))
{
paramsNode.getProperty('ametys:order-by').remove();
}
migrated++;
}
// Tag cloud on words.
query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.plugins.tagcloud.services.Words']", javax.jcr.query.Query.XPATH);
nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
var orderBy = paramsNode.getProperty('ametys:order-by').getString();
if (orderBy == 'occurrence')
{
paramsNode.setProperty('ametys:order-by', 'input');
}
migrated++;
}
session.save();
println(migrated + ' tag cloud service(s) have been migrated.');
var qm = session.getWorkspace().getQueryManager();
var migrated = 0;
// Tag cloud on tags.
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.plugins.tagcloud.services.Tags']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
if (paramsNode.hasProperty('ametys:order-by'))
{
paramsNode.getProperty('ametys:order-by').remove();
}
migrated++;
}
// Tag cloud on words.
query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.plugins.tagcloud.services.Words']", javax.jcr.query.Query.XPATH);
nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
var orderBy = paramsNode.getProperty('ametys:order-by').getString();
if (orderBy == 'occurrence')
{
paramsNode.setProperty('ametys:order-by', 'input');
}
migrated++;
}
session.save();
println(migrated + ' tag cloud service(s) have been migrated.');
var qm = session.getWorkspace().getQueryManager();
var migrated = 0;
// Tag cloud on tags.
var query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.plugins.tagcloud.services.Tags']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
if (paramsNode.hasProperty('ametys:order-by'))
{
paramsNode.getProperty('ametys:order-by').remove();
}
migrated++;
}
// Tag cloud on words.
query = qm.createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.plugins.tagcloud.services.Words']", javax.jcr.query.Query.XPATH);
nodes = query.execute().getNodes();
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
var orderBy = paramsNode.getProperty('ametys:order-by').getString();
if (orderBy == 'occurrence')
{
paramsNode.setProperty('ametys:order-by', 'input');
}
migrated++;
}
session.save();
println(migrated + ' tag cloud service(s) have been migrated.');
Proxied content service ("revamping")
The service of proxied content (or "revamping" service) has been moved to the new proxied-content plugin. If you use this service, add the plugin jars or add the dependency in your ivy.xml
Oops !
Copy to clipboard failed. Open the code and copy it manually.
Then execute the following script in administration console to migrate the existing services.
Oops !
Copy to clipboard failed. Open the code and copy it manually.
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.service.Revamping']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var node = nodes.next();
node.setProperty('ametys-internal:service', 'org.ametys.proxied-content.service.Revamping');
count++;
}
session.save();
println(count + ' service(s) of proxied content have been migrated');
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.service.Revamping']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var node = nodes.next();
node.setProperty('ametys-internal:service', 'org.ametys.proxied-content.service.Revamping');
count++;
}
session.save();
println(count + ' service(s) of proxied content have been migrated');
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.service.Revamping']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
var count = 0;
while (nodes.hasNext())
{
var node = nodes.next();
node.setProperty('ametys-internal:service', 'org.ametys.proxied-content.service.Revamping');
count++;
}
session.save();
println(count + ' service(s) of proxied content have been migrated');
Filtered contents service
The "filtered contents" service allows now to choose the sort direction for each sort criteria.If sort direction is not setted, the descending direction is used in all case even for date criteria.
The following script lists the pages containing this service and which may be needed a manual re-configuration.
Oops !
Copy to clipboard failed. Open the code and copy it manually.
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.FilteredContentsService']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
println("The following pages contain the 'filtered contents' service which the sort parameter may be migrated manually to have the desired sort direction: ");
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
if (paramsNode.hasProperty("ametys:sortBy"))
{
var sortBy = paramsNode.getProperty("ametys:sortBy").getString();
if (sortBy != '')
{
var pageNode = node.getParent().getParent().getParent().getParent();
println("* " + pageNode.getProperty("ametys-internal:title").getString() + " (" + sortBy + ")");
}
}
}
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.FilteredContentsService']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
println("The following pages contain the 'filtered contents' service which the sort parameter may be migrated manually to have the desired sort direction: ");
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
if (paramsNode.hasProperty("ametys:sortBy"))
{
var sortBy = paramsNode.getProperty("ametys:sortBy").getString();
if (sortBy != '')
{
var pageNode = node.getParent().getParent().getParent().getParent();
println("* " + pageNode.getProperty("ametys-internal:title").getString() + " (" + sortBy + ")");
}
}
}
var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:zoneItem)[@ametys-internal:type='SERVICE' and @ametys-internal:service='org.ametys.web.service.FilteredContentsService']", javax.jcr.query.Query.XPATH);
var nodes = query.execute().getNodes();
println("The following pages contain the 'filtered contents' service which the sort parameter may be migrated manually to have the desired sort direction: ");
while (nodes.hasNext())
{
var node = nodes.next();
var paramsNode = node.getNode('ametys:service_parameters');
if (paramsNode.hasProperty("ametys:sortBy"))
{
var sortBy = paramsNode.getProperty("ametys:sortBy").getString();
if (sortBy != '')
{
var pageNode = node.getParent().getParent().getParent().getParent();
println("* " + pageNode.getProperty("ametys-internal:title").getString() + " (" + sortBy + ")");
}
}
}
Help plugin
If you have a help plugin, it may use the tab_bg.png image.
Open the file plugins/help/resources/css/helptool.css. At line 20, replace
Oops !
Copy to clipboard failed. Open the code and copy it manually.