Hybris HAC Update Scenario - sap-commerce-cloud

I wrote an interceptor in one of my projects to intercept all the requests. So usually in a spring project i will do normal build and start the server and my changes related to an interceptor will start reflecting. However this doesn't seem to be the case with a hybris project.
Do I need to do update in hybris hac as well? And if I do then out of the available below mentioned options which options do i need to choose and why.
1. Update running system
2. Clear the hMC configuration from the database
3. Create essential data
4. Localize types
Thanks,
Ashish

To answer the second part of your question, I have listed at least one reason for selecting each type of options. Hope this helps.
Update running system - Required when hybris type definition changes. For example, changing the content of file <extnesion-name>-items.xml
Clear the hMC configuration from the database - If you have chosen to persist hmc configuration in the Database and changing it. For example, changing content in the file hmc.xml
Create essential data - If there is a change in the content in the impex files which follows the naming pattern of essentialdata*.impex.
Localize types - If there is a change in the properties files for localizations. for example changing the content in file <extension-name>-locales_en.properties

Assuming you've not made any changes to any underlying data objects (Jalo items) then you won't need to run an update in the hybris hAC.
You should just be able to make your changes, run ant clean all from the platform and then start up the hybris ECP instance and your changes will be visible.

If this is a normal Spring MVC interceptor, then it should work fine.
Have you checked your spring configuration in the storefront extension you are working from?
For example, take a look at the accelerator Spring MVC configuration file:
hybris/bin/ext-template/yacceleratorstorefront/web/webroot/WEB-INF/config/spring-mvc-config.xml
This has some examples where this is used out-of-the-box:
<mvc:interceptors>
<ref bean="beforeControllerHandlerInterceptor" />
<ref bean="beforeViewHandlerInterceptor" />
<ref bean="csrfHandlerInterceptor" />
</mvc:interceptors>
As an example, the default before controller handler interceptor is defined as:
<!-- Interceptor that runs once per request and before the controller handler method is called -->
<alias name="defaultBeforeControllerHandlerInterceptor" alias="beforeControllerHandlerInterceptor" />
<bean id="defaultBeforeControllerHandlerInterceptor" class="de.hybris.platform.yacceleratorstorefront.interceptors.BeforeControllerHandlerInterceptor" >
<property name="beforeControllerHandlers">
<ref bean="beforeControllerHandlersList" />
</property>
</bean>
which references:
<alias name="defaultBeforeControllerHandlersList" alias="beforeControllerHandlersList" />
<util:list id="defaultBeforeControllerHandlersList" >
<!-- List of handlers to run -->
<bean class="de.hybris.platform.yacceleratorstorefront.interceptors.beforecontroller.SecurityUserCheckBeforeControllerHandler" />
<bean class="de.hybris.platform.yacceleratorstorefront.interceptors.beforecontroller.RequireHardLoginBeforeControllerHandler" >
<property name="userService" ref="userService"/>
<property name="redirectStrategy" ref="redirectStrategy"/>
...
</bean>
<bean class="de.hybris.platform.yacceleratorstorefront.interceptors.beforecontroller.DeviceDetectionBeforeControllerHandler" />
...
</util:list>
So you could either override this using the alias with your own implementation, or add additional controller handlers to the list.
As there is no change to the underlying data model - this is just wiring up Spring MVC related classes - no need for an update system or anything like that. Just an 'ant clean all' to recompile to pick up your new interceptor classes, and server restart to pick up the change in the Spring cornfiguraton.

Related

Slow performance spring.io flow from ActiveMQ to OracleAQ with XA

I have a Spring integration flow which bridges from ActiveMQ to OracleAQ.
See example project under GitHub - https://github.com/cknzl2014/springio-ora-xa/tree/atomikos.
When I run it without XA, it is blazingly fast.
With XA, it processes only 1 to 2 messages per second.
When profiling the application, I see that for every message a new physical connection is established, and with this, the metadata query is issued on the oracle db.
But I don't understand why it does this, and how I can prevent this from happening.
Does anyone of you guys have experience with OracleAQ and XA?
Could this be a problem with the XA transaction manager (I use Atomikos)?
Thanks for your help,
Chris
We found a solution to the problem.
It consists of four steps.
Step 1: Use the latest Oracle client libraries
The first step ist to use the lastest Oracle 12c client libraries.
There were significant improvements in the ojdbc8.jar, e.g. they use stored procedures to get the metadata now.
This increased the throughput to about 10 msgs/s.
Step 2: Setup connection pooling correctly
The second step was improving the connection pooling according to article http://thinkfunctional.blogspot.ch/2012/05/atomikos-and-oracle-aq-pooling-problem.html:
<bean id="oraXaDataSource" primary="true"
class="oracle.jdbc.xa.client.OracleXADataSource" destroy-method="close">
<property name="URL" value="${oracle.url}" />
<property name="user" value="${oracle.username}" />
<property name="password" value="${oracle.password}" />
</bean>
<bean id="atomikosOraclaDataSource"
class="org.springframework.boot.jta.atomikos.AtomikosDataSourceBean">
<property name="uniqueResourceName" value="xaOracleAQ" />
<property name="xaDataSource" ref="oraXaDataSource" />
<property name="poolSize" value="5" />
</bean>
<bean id="OracleAQConnectionFactory" class="oracle.jms.AQjmsFactory" factory-method="getConnectionFactory">
<constructor-arg ref="atomikosOraclaDataSource" />
</bean>
This configuration alone resultet in exceptions because of 'auto-commit' of the Oracle connection.
Step 3: Set autoCommit to false
The third step was to set the following java system property (see https://docs.oracle.com/database/121/JAJDB/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_AUTOCOMMIT):
-DautoCommit=false
But then the throughput went down to 1 to 2 msg/s again.
Step 4: Set oracle.jdbc.autoCommitSpecCompliant to false
The last step was to set the following java system property (see https://docs.oracle.com/database/121/JAJDB/oracle/jdbc/OracleConnection.html#CONNECTION_PROPERTY_AUTO_COMMIT_SPEC_COMPLIANT):
-Doracle.jdbc.autoCommitSpecCompliant=false
Now we get a throughput of 80 msgs/s.
Conclusion
The setting of oracle.jdbc.autoCommitSpecCompliant to false is not elegant, but solved the problem.
We have to investigate further to see how we can get around this problem without setting oracle.jdbc.autoCommitSpecCompliant to false.
Many thanks to Dani Steinmann (stonie) for the help!
P.S.: I updated the sample project under GitHub - https://github.com/cknzl2014/springio-ora-xa/tree/atomikos.
First of all you should be sure that you use pool for JDBC connections.
On the other hand you may consider to use ChainedTransactionManager isntead of XA for two target transaction managers - JMS and JDBC.
Also see some information in the JDBC extensions project.
There is also some Oracle AQ API as well in that project.

How to access Backoffice in Junit Tenant

We can access HMC in JUnit tenant by hitting the below URL
https://localhost:9002/hmc_junit/hybris
which is defined in tenant_junit.properties like this hmc.webroot=/hmc_junit
But I havn't seen anywhere URL to access Backoffice in JUnit Tenant.
Can anybody help me please to access Backoffice in JUnit Tenant ?
I was looking for it everywhere as well, couldn't find any documentation in the wiki... It doesn't seem to be officially supported but here is what I found.
Under Hybris 6.3 there is no junit context path for the backoffice application. Here is how you could add one :
Create a file named : local_tenant_junit.properties under your configuration folder, it should contain :
backoffice.webroot=/backoffice_junit
Create a file for customization inside your config folder customize/ext-backoffice/backoffice/web/webroot/WEB-INF/backoffice-spring-filter.xml. Copy the content of the original file and update the backofficeFilterChain bean. We want to use the dynamicTenantActivationFilter instead of the tenantActivationFilter) :
<bean id="backofficeFilterChain" class="de.hybris.platform.servicelayer.web.PlatformFilterChain">
<constructor-arg>
<list>
<ref bean="log4jFilter"/>
<ref bean="dynamicTenantActivationFilter"/>
<ref bean="backofficeRedirectFilter"/>
<ref bean="sessionFilter"/>
<ref bean="backofficeDataSourceSwitchingFilter"/>
<ref bean="backofficeCatalogVersionActivationFilter"/>
<ref bean="backofficeContextClassloaderFilter"/>
<ref bean="backofficeSecureMediaFilter" />
</list>
</constructor-arg>
Execute ant clean all customize
Check that in bin/platform/tomcat/conf/server.xml you now have a new context backoffice_junit
Start your server, you can now access the backoffice application for master and junit tenant
For Hybris 6.7, to me the following steps were sufficient:
in config/local_tenant_junit.properties , add
backoffice.webroot=/backoffice_junit
ant server
this puts the endpoint into ${tomcat.webapps} in server.xml template resulting in:
<Context path="/backoffice_junit"...
being added to your bin/platform/tomcat/conf/server.xml
Then when you open https://localhost:9002/backoffice_junit , the DataSourceSwitchingFilter gets current tenant from a ThreadLocal and activates its dataSource.
Config values inside the junit local properties that worked for me:
backoffice.library.home=${data.home}/junit
backoffice.webroot=/junit_backoffice
For more info see:
https://help.sap.com/viewer/5c9ea0c629214e42b727bf08800d8dfa/1811/en-US/c7e1bf2832414c8ea15c001d5cf1defd.html

How to start my cron job on startup of alfresco server?

How can I start my scheduler on startup of Alfresco server?
Liferay provide onstartup server event. Is there any similar kind of functionality available in the Alfresco where can I start my Cron job on start of Alfresco server?
It does not make sense to use cron or a similar service if you want to run custom code at startup time. Add your custom Spring managed bean derived from org.springframework.extensions.surf.util.AbstractLifecycleBean to a file tomcat/shared/classes/alfresco/extension/startup-context.xml (or equivalent). Put your code in the onBootstrap method.
Another good way to to this is to extend the AbstractModuleComponent implementing the method executeInternal and in the Spring configuration set the executeOnlyOnce to false.
In this way your custom code will be executed every time Alfresco starts.
Below an example of a Spring configuration:
<bean id="initJobsComponent" class="com.sourcesense.alfresco.component.InitJobsComponent" parent="module.baseComponent" >
<property name="moduleId" value="myModuleId" />
<property name="name" value="initComponent" />
<property name="description" value="You description" />
<property name="sinceVersion" value="1.0" />
<property name="appliesFromVersion" value="1.0" />
<property name="executeOnceOnly" value="false"/>
</bean>
Your Java class must extend AbstractModuleComponent:
public class InitJobsComponent extends AbstractModuleComponent {
...
#Override
protected void executeInternal() throws Throwable {
//put here your custom code
}
...
}
Hope this helps.
To fit your need you could launch execution of your job by appending it to alfresco launch script.
Edit :
/etc/init.d/alfresco
Put into "start" section your job, example:
case $1 in
start)
sh YOUR_CRON_JOB
[....]
;;

Adding script maps during installation of web application IIS

has anyone successfully added IIS script maps to their Wix installation. I have been using this:
<CustomAction Id="AddHandlers_Cmd" Property="AddHandlers" Value=""[SystemFolder]inetsrv\appcmd" set config -section:system.webServer/handlers /+"[\[]name='GSOAP',path='*.dll', verb='*',modules='IsapiModule',scriptProcessor='[BIN]mod_gsoap.dll',resourceType='File', requireAccess='Execute'[\]]"" Execute="immediate"/>
<CustomAction Id="AddHandlers" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no"/>
However I get the 404 errors from my web application and when I add the script map manually after installing the application it works perfectly. I would appreciate if anyone could share how they done this.
It sounds like you need to add handler mapping to your web application. If that's the case, then you don't need a custom action to accomplish this.
Take a look at WebApplicationExtension element.
We are writing a separate Custom action in C# and Schedule it in after install Finalize to add handlers.
Try this, you can do anything with your own custom action.
I haven't worked with GSOAP handler, but used ASP.NET ISAPI extention. I suppose basically it has the same level of integration. I will post the code for ASP.NET and I hope you won't have problem with changing it to GSOAP. I have a huge risk of changing something incorrectly and make the examples unusable for you, so I let you do it better.
Here is my code to register extention itself if it isn't
<Component Id="Iis6ConfigExtentions" Guid="{GuidHash({ProductId}-1822E4F3-5850-47D5-9281-D1E0E20C77D4)}" KeyPath="yes" Permanent="yes">
<Condition><![CDATA[Installed OR (IISMAJORVERSION AND (IISMAJORVERSION = "#6"))]]></Condition>
<iis:WebServiceExtension Id="ExtensionASP4" Group="ASP.NET v4.0.30319" Allow="yes" File="[FRAMEWORKROOT]v4.0.30319\aspnet_isapi.dll" Description="ASP.NET v4.0.30319"/>
</Component>
and for adding those to the concrete site you need to use WebApplicationExtention, as #Yan already mentioned:
<iis:WebApplication Id="IIS6WebApp" Name="[SITE_APP_NAME]" WebAppPool="AppPool" >
<iis:WebApplicationExtension Verbs="GET,HEAD,POST" CheckPath="no" Script="yes" Executable="[FRAMEWORKROOT]v4.0.30319\aspnet_isapi.dll" />
</iis:WebApplication>
The CheckPath="no" is required on IIS 6 because we use ASP.NET MVC which doesn't map urls to files on disk. You might need it too since service address probably doesn't map to physical file.
UPDATE:
Looks like it is really not possible to do it directly in WIX (at least in 3.5 version). You are going in right direction - custom action using appcmd. But the provided custom actions aren't complete or what you need: the first one just sets property value to the command you need to execute and the second one calls some Dll custom action which wasn't provided.
What I'd try to execute is:
<CustomAction Id="AddGsoapHandler" Directory="TARGETDIR" Impersonate="no" Execute="deferred" Return="check" ExeCommand="[SystemFolder]inetsrv\appcmd.exe set config -section:system.webServer/handlers /+"[\[]name='GSOAP',path='*.dll', verb='*',modules='IsapiModule',scriptProcessor='[BIN]mod_gsoap.dll',resourceType='File', requireAccess='Execute'[\]]" /commit:apphost" />
Please pay attention to the path attribute of your handler configuration. It will limit handler usage to only URL's which ends with ".dll" - I just copied it from your code but not sure if you've done it intentionally or just copied from example at Microsoft site. That might have led to 401 error even if handler is registered successfully.
Also I added the /commit:apphost argument. Not sure if you really need this, but I use it to explicitly specify that I need to configure my application's config.
UPDATE 2:
If you need to set configuration to only single application, you should specify application object as argument of appcmd instead of the 'config' which means global configuration. Please try this:
<CustomAction Id="AddGsoapHandler" Directory="TARGETDIR" Impersonate="no" Execute="deferred" Return="check" ExeCommand="[SystemFolder]inetsrv\appcmd.exe set app "MySite/app1" -section:system.webServer/handlers /+"[\[]name='GSOAP',path='*.dll', verb='*',modules='IsapiModule',scriptProcessor='[BIN]mod_gsoap.dll',resourceType='File', requireAccess='Execute'[\]]" /commit:apphost" />
For more details you can read this tutorial.

Externalizing Tomcat webapp config from .war file

I am having trouble with configuring a webapp in Tomcat 7. In my WAR file, there is a properties file myApp/WEB-INF/classes/myProps.props, and it contains environment-specific properites. I am trying to override that configuration file on the server, so that the same WAR file will deploy to multiple environments.
I heard there was a way to do this using replacement config files in tomcat/conf/Catalina/myApp. This is the method I am having trouble figuring out.
Also, myApp.war is one of many running on the same Tomcat server, and it does not run as localhost. I want to be able to solve this problem for several of the webapps.
Server version: Apache Tomcat/7.0.23
Server built: Nov 20 2011 07:36:25
Server number: 7.0.23.0
OS Name: Linux
Your tomcat/conf/Catalina/<host> can contain context descriptors that let you configure lots of things including defining "environment entries", which are accessible from Java via JNDI. There are lots of ways to go about using it. Personally, I set an environment entry which is the file system path to my properties file. My app is built to check for this entry, and if it doesn't exist, look for the file on the classpath instead. That way, in dev, we have the dev properties right there on the classpath, but when we build and deploy, we point it to an external file.
There's good documentation for configuring a context on the Tomcat website. See the Defining a Context section on details of how to create the file and where to put it.
As an example, if your host is named myHost and your app is a war file named myApp.war in the webapps directory, then you could create tomcat/conf/Catalina/myHost/myApp.xml with this content:
<Context>
<Environment name="configurationPath" value="/home/tomcat/myApp.properties" type="java.lang.String"/>
</Context>
Then from your code, you'd do a JNDI lookup on java:comp/env/configurationPath (95% certainty here) to get that string value.
I like .properties files instead of
JNDI - why build complex object during program configuration instead of initialization time?
system properties - you can't separately configure several instances of same WAR in single Tomcat
context parameters - they accessible only in javax.servlet.Filter, javax.servlet.ServletContextListener which my be inconvenient
Tomcat 7 Context hold Loader element. According to docs deployment descriptor (what in <Context> tag) can be placed in:
$CATALINA_BASE/conf/server.xml - bad - require server restarts in order to reread config
$CATALINA_BASE/conf/context.xml - bad - shared across all applications
$CATALINA_BASE/work/$APP.war:/META-INF/context.xml - bad - require repackaging in order to change config
$CATALINA_BASE/work/[enginename]/[hostname]/$APP/META-INF/context.xml - nice, but see last option!!
$CATALINA_BASE/webapps/$APP/META-INF/context.xml - nice, but see last option!!
$CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml - best - completely out of application and automatically scanned for changes!!!
Context can hold custom Loader org.apache.catalina.loader.VirtualWebappLoader (available in modern Tomcat 7, you can add own separate classpath to your .properties), and Parameter (accessed via FilterConfig.getServletContext().getInitParameter(name)) and Environment (accessed via new InitialContext().lookup("java:comp/env").lookup("name")):
<Context docBase="${basedir}/src/main/webapp"
reloadable="true">
<!-- http://tomcat.apache.org/tomcat-7.0-doc/config/context.html -->
<Resources className="org.apache.naming.resources.VirtualDirContext"
extraResourcePaths="/WEB-INF/classes=${basedir}/target/classes,/WEB-INF/lib=${basedir}/target/${project.build.finalName}/WEB-INF/lib"/>
<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
virtualClasspath="${basedir}/target/classes;${basedir}/target/${project.build.finalName}/WEB-INF/lib"/>
<JarScanner scanAllDirectories="true"/>
<Parameter name="min" value="dev"/>
<Environment name="app.devel.ldap" value="USER" type="java.lang.String" override="true"/>
<Environment name="app.devel.permitAll" value="true" type="java.lang.String" override="true"/>
</Context>
If you use Spring and it's XML config:
<context:property-placeholder location="classpath:app.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#${db.host}:${db.port}:${db.user}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.pass}"/>
</bean>
With Spring injecting above properties into bean fields are easy:
#Value("${db.user}") String defaultSchema;
instead of JNDI:
#Inject ApplicationContext context;
Enviroment env = context.getEnvironment();
String defaultSchema = env.getProperty("db.user");
Note also that EL allow this (default values and deep recursive substitution):
#Value('${db.user:testdb}') private String dbUserName;
<property name='username' value='${db.user.${env}}'/>
See also:
Adding a directory to tomcat classpath
Can I create a custom classpath on a per application basis in Tomcat
How to read a properties file outside my webapp context in Tomcat
Configure Tomcat to use properties file to load DB connection information
Should you set up database connection properties in server.xml or context.xml
Externalize Tomcat configuration
NOTE With extending classpath to live directory you also allowed to externilize any other configs, like logging, auth, atc. I externilize logback.xmlin such way.
UPDATE Tomcat 8 change syntax for <Resources> and <Loader> elements, corresponding part now look like:
<Resources>
<PostResources className="org.apache.catalina.webresources.DirResourceSet"
webAppMount="/WEB-INF/classes" base="${basedir}/target/classes" />
<PostResources className="org.apache.catalina.webresources.DirResourceSet"
webAppMount="/WEB-INF/lib" base="${basedir}/target/${project.build.finalName}/WEB-INF/lib" />
</Resources>
You can try to place your configuration (properties file) in Apache Tomcat\lib in JAR file and remove it from the web application. When the Tomcat's class loader won't find your config in webapp it will try to find in "lib" directory. So you can externalize your configuration just moving the config to global lib dir (it's shared among other webapps).
I just added a setenv.bat or setenv.sh script in the bin folder of tomcat. Set the classpath variable like
set CLASSPATH=my-propery-folder

Resources