Java VDM generator does not work properly for API_SALES_ORDER_SIMULATION_SRV with SAP Cloud SDK version 3.7.0 - sap-cloud-sdk

I am using Java VDM Generator to generate service classes with SAP Cloud SDK archetype project and the version is 3.7.0.
The OData service I used is API_SALES_ORDER_SIMULATION_SRV. I downloaded the metadata from SAP API Business Hub. Actually I also tested the metadata on S/4HANA on-premise 1909. The issue still exists.
The plugin I used to in pom.xml is as below:
<plugin>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-generator-maven-plugin</artifactId>
<version>3.7.0</version>
<executions>
<execution>
<id>generate-consumption</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputDirectory>${project.basedir}/edmx</inputDirectory>
<outputDirectory>${project.build.directory}/vdm</outputDirectory>
<deleteOutputDirectory>true</deleteOutputDirectory>
<defaultBasePath>/sap/opu/odata/sap/</defaultBasePath>
<packageName>com.bosch.testvdm</packageName>
<serviceNameMappingFile>${project.basedir}/serviceNameMappings.properties</serviceNameMappingFile>
<compileScope>COMPILE</compileScope>
</configuration>
</execution>
</executions>
</plugin>
The service interface/class generated are APISALESORDERSIMULATIONSRVService and DefaultAPISALESORDERSIMULATIONSRVService. Some methods are lost in the service. E.g. createSalesOrderSimulationAPI().
/*
* Generated by OData VDM code generator of SAP Cloud SDK in version 3.7.0
*/
package com.bosch.testvdm.services;
import javax.annotation.Nonnull;
import com.bosch.testvdm.namespaces.salesordersimulationsrv.batch.APISALESORDERSIMULATIONSRVServiceBatch;
import com.sap.cloud.sdk.datamodel.odata.helper.batch.BatchService;
/**
* <h3>Details:</h3><table summary='Details'><tr><td align='right'>OData Service:</td><td>API_SALES_ORDER_SIMULATION_SRV</td></tr></table>
*
*/
public interface APISALESORDERSIMULATIONSRVService
extends BatchService<APISALESORDERSIMULATIONSRVServiceBatch>
{
/**
* If no other path was provided via the {#link #withServicePath(String)} method, this is the default service path used to access the endpoint.
*
*/
String DEFAULT_SERVICE_PATH = "/sap/opu/odata/sap/API_SALES_ORDER_SIMULATION_SRV";
/**
* Overrides the default service path and returns a new service instance with the specified service path. Also adjusts the respective entity URLs.
*
* #param servicePath
* Service path that will override the default.
* #return
* A new service instance with the specified service path.
*/
#Nonnull
APISALESORDERSIMULATIONSRVService withServicePath(
#Nonnull
final String servicePath);
}
/*
* Generated by OData VDM code generator of SAP Cloud SDK in version 3.7.0
*/
package com.bosch.testvdm.services;
import javax.annotation.Nonnull;
import javax.inject.Named;
import com.bosch.testvdm.namespaces.salesordersimulationsrv.batch.DefaultAPISALESORDERSIMULATIONSRVServiceBatch;
/**
* <h3>Details:</h3><table summary='Details'><tr><td align='right'>OData Service:</td><td>API_SALES_ORDER_SIMULATION_SRV</td></tr></table>
*
*/
#Named("com.bosch.testvdm.services.DefaultAPISALESORDERSIMULATIONSRVService")
public class DefaultAPISALESORDERSIMULATIONSRVService
implements APISALESORDERSIMULATIONSRVService
{
#Nonnull
private final String servicePath;
/**
* Creates a service using {#link APISALESORDERSIMULATIONSRVService#DEFAULT_SERVICE_PATH} to send the requests.
*
*/
public DefaultAPISALESORDERSIMULATIONSRVService() {
servicePath = APISALESORDERSIMULATIONSRVService.DEFAULT_SERVICE_PATH;
}
/**
* Creates a service using the provided service path to send the requests.
* <p>
* Used by the fluent {#link #withServicePath(String)} method.
*
*/
private DefaultAPISALESORDERSIMULATIONSRVService(
#Nonnull
final String servicePath) {
this.servicePath = servicePath;
}
#Override
#Nonnull
public DefaultAPISALESORDERSIMULATIONSRVService withServicePath(
#Nonnull
final String servicePath) {
return new DefaultAPISALESORDERSIMULATIONSRVService(servicePath);
}
/**
* {#inheritDoc}
*
*/
#Override
#Nonnull
public DefaultAPISALESORDERSIMULATIONSRVServiceBatch batch() {
return new DefaultAPISALESORDERSIMULATIONSRVServiceBatch(this);
}
}
It works fine with SAP Cloud SDK version 3.3.1. All the methods are generated in the service.
By the way, it is weird that it is working fine for some OData services with version 3.7.

Update: Version 3.9.0 of the SAP Cloud SDK is available, containing the fix for this issue.
I had a look at this and found out that a new feature we added between those versions results in unexpected behavior.
For a quick workaround you could try to remove the <annotation> blocks usually found at the end of the your edmx file.
We are looking into a fix for this and I will update this question once we have a fix available.

Related

Maximo Event Filter Java class not being picked up by Publish Channel

I have written a Java class for event filtering on one of the Publish channels, and rebuilt and deployed it. I have referenced it on the Publish channel too. However, Maximo behaves as if the class was never there.
package com.sof.iface.eventfilter;
import java.rmi.RemoteException;
import psdi.iface.mic.MaximoEventFilter;
import psdi.iface.mic.PublishInfo;
import psdi.mbo.MboRemote;
import psdi.util.MXException;
import psdi.util.logging.MXLogger;
import psdi.util.logging.MXLoggerFactory;
public class VSPPWOCOMPEventFilter extends MaximoEventFilter {
private static final String SILMX_ATTRIBUTE_STATUS = "STATUS";
private MXLogger log = MXLoggerFactory.getLogger("maximo.application.EVENTFILTER");
/**
* Constructor
*
* #param pubInfo Publish Channel Information
* #throws MXException Maximo Exception
*/
public VSPPWOCOMPEventFilter(PublishInfo pubInfo) throws MXException {
super(pubInfo);
} // end constructor.
/**
* Decide whether to filter out the event before it triggers the
* Publish Channel or not.
*/
public boolean filterEvent(MboRemote mbo) throws MXException, RemoteException {
log.debug("######## com.sof.iface.eventfilter.VSPPWOCOMPEventFilter::filterEvent() - Start of Method");
boolean filter = false;
// try {
String status = mbo.getString(SILMX_ATTRIBUTE_STATUS);
log.debug("######## com.sof.iface.eventfilter.VSPPWOCOMPEventFilter::filterEvent() - WO Status " + status);
if(mbo.isModified("STATUS") && status == "COMP") {
log.debug("######## com.sof.iface.eventfilter.VSPPWOCOMPEventFilter::filterEvent() - Skipping MBO");
filter = true;
} else {
filter = super.filterEvent(mbo);
}
log.debug("######## com.sof.iface.eventfilter.VSPPWOCOMPEventFilter::filterEvent() - End of Method");
return filter;
// }
} // end filterEvent.
} // end class.
Please ignore the below text :)
A good logging (tracing) is always a lifesaver when you have problems in a production environment. I will never stop telling to my fellow programmers how much is important to fill code with meaningful log calls.Maximo has a good and flexible logging subsystem. This IBM TechNote describes in detail how logging works in Maximo. Let’s now see hot to use Maximo logging in your custom Java code.
It looks like you need to skip the outbound message when the Work Order is completed. When the event doesn't seem to occur, make sure to check for these flags:
External System is active
Publish Channel is active
Publish Channel listener is enabled
I think you could easily achieve the same result with a SKIP action processing rule. See details here:
https://www.ibm.com/support/knowledgecenter/en/SSLKT6_7.6.0/com.ibm.mt.doc/gp_intfrmwk/c_message_proc_actions.html
Also worth mentioning: IBM added automation script support for Event Filtering in version 7.6 so no more build/redeploy required.

Records are not consumed when adding checkpointer

I have following configuration for KinesisMessageDrivenChannelAdapter, when I remove dynamoDbMetaDataStore as checkpointer, messages are received correctly, but when I add it back records are always empty.
I debugged the code and KinesisMessageDrivenChannelAdapter.processTask() line 776 (version 2.0.0.M2) returns empty records.
UPDATE:
public DynamoDbMetaDataStore dynamoDbMetaDataStore() {
String url = consumerClientProperties.getDynamoDB().getUrl();
final AmazonDynamoDBAsync amazonDynamoDB = AmazonDynamoDBAsyncClientBuilder.standard()
.withEndpointConfiguration(new EndpointConfiguration(
url,
Regions.fromName(awsRegion).getName()))
.withClientConfiguration(new ClientConfiguration()
.withMaxErrorRetry(consumerClientProperties.getDynamoDB().getRetries())
.withConnectionTimeout(consumerClientProperties.getDynamoDB().getConnectionTimeout())).build();
DynamoDbMetaDataStore dynamoDbMetaDataStore = new DynamoDbMetaDataStore(amazonDynamoDB, "consumer-test");
return dynamoDbMetaDataStore;
}
public KinesisMessageDrivenChannelAdapter kinesisInboundChannel(
AmazonKinesis amazonKinesis, String[] streamNames) {
KinesisMessageDrivenChannelAdapter adapter =
new KinesisMessageDrivenChannelAdapter(amazonKinesis, streamNames);
adapter.setConverter(null);
adapter.setOutputChannel(kinesisReceiveChannel());
adapter.setCheckpointStore(dynamoDbMetaDataStore());
adapter.setConsumerGroup(consumerClientProperties.getName());
adapter.setCheckpointMode(CheckpointMode.manual);
adapter.setListenerMode(ListenerMode.record);
adapter.setStartTimeout(10000);
adapter.setDescribeStreamRetries(1);
adapter.setConcurrency(10);
return adapter;
}
Thank you
I recommend you to test your solution with the latest 2.0.0.BUILD-SNAPSHOT.
There is already an option like:
/**
* Specify a {#link LockRegistry} for an exclusive access to provided streams.
* This is not used when shards-based configuration is provided.
* #param lockRegistry the {#link LockRegistry} to use.
* #since 2.0
*/
public void setLockRegistry(LockRegistry lockRegistry) {
where you would need to inject a DynamoDbLockRegistry for better checkpoint management.
For that purpose you would also need to add this dependency:
compile("com.amazonaws:dynamodb-lock-client:1.0.0")
There indeed might be some issues with filtering in that M2 yet...

Shopware plugin works on 5.2 and 5.3 but doesnt work on 5.1.6

I have a plugin which works on shopware 5.2 and 5.3 but doesnt work on 5.1.6. Here is the start file which is called ebTaxApi.php and i believe something should be changed here, but I need help:
<?php
namespace ebTaxApi;
use Shopware\Components\Plugin;
class ebTaxApi extends Plugin
{
/**
* #inheritdoc
*/
public static function getSubscribedEvents()
{
return [
'Enlight_Controller_Dispatcher_ControllerPath_Api_Tax' => 'onGetTaxApiController',
'Enlight_Controller_Front_StartDispatch' => 'onEnlightControllerFrontStartDispatch'
];
}
/**
* #return string
*/
public function onGetTaxApiController()
{
return $this->getPath() . '/Controllers/Api/Tax.php';
}
/**
*
*/
public function onEnlightControllerFrontStartDispatch()
{
$this->container->get('loader')->registerNamespace('Shopware\Components', $this->getPath() . '/Components/');
}
}
THis plugin is verified and works on 5.2 and 5.3 but i have tried to make its way into 5.1.6 but no luck. Also tried to register the namespace using a function but didnt work, the class could not be found.
Any help?
Thanks
The Plugin-Class you are showing here is based on the new Plugin-System, wich was introduced in Shopware Version 5.2. If you need your Plugin in older Shopware versions, you need to use the legacy plugin system.

Symfony 2 SecurityContext class deprecated

I get the following error when I try to reach app/example on symfony demo
Error: The Symfony\Component\Security\Core\SecurityContext class is
deprecated since version 2.6 and will be removed in 3.0. Use
Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage
or Symfony\Component\Security\Core\Authorization\AuthorizationChecker
instead.
The server is returning the right answer with a 200 status code though.
I've found nothing on Google about it. Has anybody encounter this error before and/or know how to fix it ?
Explanation
Starting with Symfony 2.6 the SecurityContext got split into the TokenStorage and the AuthorizationChecker (see: Symfony Blog - "New in Symfony 2.6: Security component improvements").
The main reason for this was to prevent circular reference which occurred quite often when injecting the SecurityContext into your own services.
Solution
The change itself is 100% backwards compatible (as stated in the linked blog post), you just need to rewrite how you accessed the SecurityContext.
// Symfony 2.5
$user = $this->get('security.context')->getToken()->getUser();
// Symfony 2.6
$user = $this->get('security.token_storage')->getToken()->getUser();
// Symfony 2.5
if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) { ... }
// Symfony 2.6
if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { ... }
You can simply try to find the culprit by doing a text-search for security.context or SecurityContext in your source code (including the vendor directory).
But as you stated that you're using vanilla Symfony 2.6 it seems that it simply uses some soon to be deprecated methods. So you might simply use this...
Workaround
As Symfony does it's deprecation by triggering E_USER_DEPRECATED errors, you can simply disable them when booting your Symfony AppKernel:
// app/AppKernel.php
class AppKernel extends Kernel
{
public function __construct($environment, $debug) {
// Keep error reporting like it was and disable only deprecation warnings.
error_reporting(error_reporting() & (-1 ^ E_DEPRECATED));
// ...
}
}
I personally like the deprecation warnings, because Symfony's changelogs tend to give very detailed information on how you need to change your code to support future versions of Symfony and the deprecation warnings normally are triggered months before the methods are actually deprecated.
It's not a proper error, just a warning.
A deprecated class is a class that is planned to be removed in future releases (of Symfony, in this case).
It suggest you to stop using it, and points you to the newer (and substitutes) class, TokenStorage and AuthorizationChecker, that will take completly over to do the same tasks.
It gets so annoying to see that warning. At the same time you don't want to turn off the warnings. So I thought maybe it's useful to give an example of changing your code to get rid of it. Here's how I changed HWIOAuthBundle's OAuthUtils class to do so.
First, I changed /vendor/hwi/oauth-bundle/HWI/Bundle/OAuthBundle/Resources/config/oauth.html from this:
<service id="hwi_oauth.security.oauth_utils" class="%hwi_oauth.security.oauth_utils.class%">
<argument type="service" id="security.http_utils" />
<argument type="service" id="security.context" />
<argument>%hwi_oauth.connect%</argument>
</service>
to this:
<service id="hwi_oauth.security.oauth_utils" class="%hwi_oauth.security.oauth_utils.class%">
<argument type="service" id="security.http_utils" />
<argument type="service" id="security.authorization_checker" />
<argument>%hwi_oauth.connect%</argument>
</service>
Now we have to change it in the /vendor/hwi/oauth-bundle/HWI/Bundle/OAuthBundle/Security/OAuthUtils class from this:
use Symfony\Component\Security\Core\SecurityContextInterface;
...
/**
* #var SecurityContextInterface
*/
private $securityContext;
/**
* #param HttpUtils $httpUtils
* #param SecurityContextInterface $securityContext
* #param boolean $connect
*/
public function __construct(HttpUtils $httpUtils, SecurityContextInterface $securityContext, $connect)
{
$this->httpUtils = $httpUtils;
$this->securityContext = $securityContext;
$this->connect = $connect;
}
to this:
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
...
/**
* #var AuthorizationChecker
*/
private $authorizationChecker;
/**
* #param HttpUtils $httpUtils
* #param AuthorizationChecker $authorizationChecker
* #param boolean $connect
*/
public function __construct(HttpUtils $httpUtils, AuthorizationChecker $authorizationChecker, $connect)
{
$this->httpUtils = $httpUtils;
$this->authorizationChecker = $authorizationChecker;
$this->connect = $connect;
}
Then I made changes where the securityContext was used. Replaced it with authorizationChecker.
public function getAuthorizationUrl(Request $request, $name, $redirectUrl = null, array $extraParameters = array())
{
$resourceOwner = $this->getResourceOwner($name);
if (null === $redirectUrl) {
if (!$this->connect || !$this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
$redirectUrl = $this->httpUtils->generateUri($request, $this->ownerMap->getResourceOwnerCheckPath($name));
} else {
$redirectUrl = $this->getServiceAuthUrl($request, $resourceOwner);
}
}
return $resourceOwner->getAuthorizationUrl($redirectUrl, $extraParameters);
}
The reason of replacing SecurityContext with AuthorizationChecker is because only isGranted method is used in this case. Maybe you could replace it with TokenStorage or use both AuthorizationChecker and TokenStorage if you needed for your case.

Spring Integration - Spel Mapping of Gateway Parameters

I have the following interface, who's implementation will encrypt a file at a specific path.
package xx.messaging.fileTransfer;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.annotation.Payload;
/**
* <H1>FileEncryptionService</H1>
*/
public interface FileEncryptionService {
/**
* Generates a new encrypted filename based on the input, calls the default method and returns
* the encrypted file name
* #param srcFilename
* #return
* #throws Exception
*/
#Gateway
public String encryptFile(#Payload String srcFilename) throws Exception;
/**
* Encrypt the a file
* #param srcFilename The source file name
* #param destFilename The target file name
*/
#Gateway
public void encryptFile(#Payload String srcFilename, #Header("encryptedFilename") String destFilename);
}
The service will be called via the spring integration and is registered in the context as a gateway via
<int:gateway service-interface="lu.scoteqint.messaging.fileTransfer.FileEncryptionService"/>
The implementing bean and service-activator are registered as
<beans:bean id="fileEncryptionService" class="xx.messaging.fileTransfer.impl.CommandLineEncryptionService"/>
<int:service-activator
input-channel="file1"
output-channel="file2"
expression="#fileEncryptionService.encryptFile(payload)"/>
I'm expecting that the message payload is the string path to the file, since the wire-tag log shows
2013-02-05 15:50:26,911 DEBUG [org.springframework.integration.handler.LoggingHandler] (task-scheduler-1) [Payload=.\src\test\resources\test\xx.xml][Headers={timestamp=1360079426907, id=1c3be020-fc6d-42ba-b3f0-5b963f76fb76}]
But it seems the 'service-activator' expression finds a File.
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1004E:(pos 31): Method call: Method encryptFile(java.io.File) cannot be found on lu.scoteqint.messaging.fileTransfer.impl.CommandLineEncryptionService type
at org.springframework.expression.spel.ast.MethodReference.findAccessorForMethod(MethodReference.java:182)
at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:106)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:57)
at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:102)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:102)
at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:126)
at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:86)
... 30 more
EDIT
The log detail
2013-02-05 16:26:42,737 DEBUG [org.springframework.integration.channel.DirectChannel] (task-scheduler-1) preSend on channel 'file1', message: [Payload=.\src\test\resources\test.xml][Headers={timestamp=1360081602736, id=877407f6-c5a2-4bea-9ec7-f970b09f08a8}]
Is there a way to ensure the parameter is mapped as a String rather than a File?

Resources