How do I skip certain ValidateInterceptor? - sap-commerce-cloud

I have created a VariantValueCategory and wanted to skip the ValidateInterceptor as it was not allowing me to create VariantValueCategory either by Impex or by HMC. Can any one suggest me how do I skip ValidateInterceptor or any Interceptor?

Answer for hybris >= v6
Check Mouad El Fakir's answer for previous version
You can disable interceptor through code and Impex.
Using code
You can run your save model code using sessionService.executeInLocalViewWithParams and you can use parameters to avoid to use interceptors.
There are 3 types of policies :
InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_BEANS : to disable a list of beans
InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_TYPES : to disable a kind of interceptor - validator for example
InterceptorExecutionPolicy.DISABLED_UNIQUE_ATTRIBUTE_VALIDATOR_FOR_ITEM_TYPES : to disable UniqueAttributesValidatoron a set of type
Example 1 - Disable beans
final Map<String, Object> params = ImmutableMap.of(InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_BEANS, ImmutableSet.of("yourDataInterceptorToDisable"));
sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody()
{
#Override
public void executeWithoutResult()
{
//Do your stuff
modelService.save(something); // save successful - yourDataInterceptor interceptor is disabled
}
});
Example 2 - Disable interceptors type
final Map<String, Object> params = ImmutableMap.of(InterceptorExecutionPolicy.DISABLED_INTERCEPTOR_TYPES,
ImmutableSet.of(InterceptorExecutionPolicy.DisabledType.VALIDATE));
sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody()
{
#Override
public void executeWithoutResult()
{
//Do your stuff
modelService.save(something); // save successful - all validate interceptors are disabled
}
});
Example 3 - Disable by type
final Map<String, Object> params = ImmutableMap.of(InterceptorExecutionPolicy.DISABLED_UNIQUE_ATTRIBUTE_VALIDATOR_FOR_ITEM_TYPES, ImmutableSet.of("YourType"));
sessionService.executeInLocalViewWithParams(params, new SessionExecutionBody()
{
#Override
public void executeWithoutResult()
{
//Do your stuff
modelService.save(something); // save successful - UniqueAttributesValidator not called
}
});
Using Impex
It's the same thing with impex you can add 3 parameters to achieve the same thing as code
Example 1 - Disable beans [disable.interceptor.beans='yourDataInterceptorToDisable']
INSERT_UPDATE YourType[disable.interceptor.beans='yourDataInterceptorToDisable'];isocode[unique=true];toto;titi;
;something;toto;titi;
Example 2 - Disable interceptors type [disable.interceptor.types=validate]
INSERT_UPDATE YourType[disable.interceptor.types=validate];isocode[unique=true];toto;titi;
;something;toto;titi;
Example 3 - Disable by type [disable.UniqueAttributesValidator.for.types='YourType']
INSERT_UPDATE YourType[disable.UniqueAttributesValidator.for.types='YourType'];isocode[unique=true];toto;titi;
;something;toto;titi;
Ref : https://help.hybris.com/6.3.0/hcd/9ce1b60e12714a7dba6ea7e66b4f7acd.html

Actually there are two modes of importing data with ImpEx in Hybris :
Active mode : it uses the ServiceLayer to do import. It means that actions like INSERT, UPDATE and REMOVE are performed using ModelService, thus the ServiceLayer infrastructure like interceptors and validators are triggered.
Legacy mode : it's a very quick CRUDE import, which means it's bypassing the ServiceLayer of Hybris, hence no interceptors and no validators are invoked.
So how to enable legacy mode ? will You can do this in three different ways :
In local.properties set impex.legacy.mode = true and restart the server.
<!-- local.properties -->
impex.legacy.mode = true
Or if you do import using HAC, check legacy mode checkbox :
Or set the configuration directly into theimpex like this :
INSERT_UPDATE VariantValueCategory[impex.legacy.mode=true] ;myAttribute
...
However if you want to disable completely the interceptor from being called (not just for impexes), you can replace it with a VoidInterceptor.
VoidInterceptor : it's an empty interceptor, it does nothing at all.
So if we suppose that you want to prevent this interceptor variantCategoryValidateInterceptor from being invoked, you can replace it like this :
<!-- in my*-spring.xml -->
<bean id="variantValueCategoryVoidInterceptorMapping" class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor" ref="VoidInterceptor"/>
<property name="typeCode" value="VariantValueCategory"/>
<property name="replacedInterceptors" ref="variantCategoryValidateInterceptor"/>
</bean>

The simpliest way: unregisterInterceptor
Go to HAC -> Scripting Languages -> Groovy
def inteceptorMapping = spring.getBean("yourInterceptorMappingBeanId")
registry = spring.getBean("interceptorRegistry");
registry.unregisterInterceptor(inteceptorMapping);

Related

How to skip the setting of 'filter' and 'locker' attribute if custom DirectoryScanner is used in Spring Integration 4.2.0 with XML Config

With Spring Integration 4.2.0, it mentioned that 'filter' and 'locker' must be present if custom Scanner is being used (https://jira.spring.io/browse/INT-3619).
I don't know how to set this with XML config if I simply override the listEligibleFiles() method and use the default filters provided by DefaultDirectoryScanner.
e.g.
// using the default filters
public class MyDirectoryScanner extends DefaultDirectoryScanner {
#Override
protected File[] listEligibleFiles(File directory) throws IllegalArgumentException {
return super.listEligibleFiles(directory);
}
}
<bean id="myCustomScanner"
class="com.company.MyDirectoryScanner" />
<int-file:inbound-channel-adapter directory="my_directory"
prevent-duplicates="true"
scanner="myCustomScanner"
channel="myChannel">
<int:poller fixed-rate="10"
time-unit="SECONDS" max-messages-per-poll="5" />
</int-file:inbound-channel-adapter>
It's not clear what you mean; that JIRA was to fix a bug where those properties were incorrectly overridden.
When injecting a custom scanner, you need to set those properties on your scanner rather than via the namespace.
use the default filters provided by DefaultDirectoryScanner.
The DefaultDirectoryScanner has the code:
public DefaultDirectoryScanner() {
final List<FileListFilter<File>> defaultFilters = new ArrayList<FileListFilter<File>>(2);
defaultFilters.add(new IgnoreHiddenFileListFilter());
defaultFilters.add(new AcceptOnceFileListFilter<File>());
this.filter = new CompositeFileListFilter<File>(defaultFilters);
}
So, if you would like do not use AcceptOnceFileListFilter (or any other default) you should follow with the recommendation from the Docs and use setFilter() of the DirectoryScanner contract. For this purpose there is FileListFilterFactoryBean with the setPreventDuplicates() to be set to false.
And yes, remove, please, prevent-duplicates="true" from your configuration, because it is prohibited, when scanner is in use:
Assert.state(!(this.scannerExplicitlySet && (this.filter != null || this.locker != null)),
"The 'filter' and 'locker' options must be present on the provided external 'scanner': "
+ this.scanner);
The filter can be set to null on the DefaultDirectoryScanner by the way...
I'm converting the JIRA to Documentation just to be more clear on the matter.

How do I apply a custom ServiceStack RequestFilterAttribute to an auto-generated Service?

I have a custom RequestFilterAttribute that I am applying to my ServiceStack services:
[MyCustomAttribute]
public class MyService : ServiceStack.Service {...
I have recently begun using the AutoQuery feature (which is awesome) but I'm wondering how to apply MyCustomAttribute to the auto-generated services that you "get for free" when your request DTO inherits from QueryBase.
I could certainly add methods to my service with the "magic" AutoQuery code:
SqlExpression<DTO> sqlExpression = AutoQuery.CreateQuery(request, Request.GetRequestParams());
QueryResponse<DTO> response = AutoQuery.Execute(request, sqlExpression);
but I'm hoping there's a better way?
If you wanted to customize the AutoQuery behavior you should first take a look at the extensibility options using Query Filters provides.
Otherwise you should be able to add the RequestFilter Attribute to the Request DTO itself, i.e:
[MyCustomAttribute]
public class MyQuery : QueryBase<Poco> {}
Alternatively you can get a reference to the auto-generated Service using:
var autoQueryService = appHost.Metadata.GetServiceTypeByRequest(typeof(MyQuery));
And then use the dynamic API to add custom attributes to it, e.g:
autoQueryService
.AddAttributes(new MyCustomAttribute { ... });
Since the Services are only generated and registered once the AutoQueryFeature Plugin is executed you'll only be able to access the service after all plugins are loaded which you can do:
1) In your own plugin by implementing the IPostInitPlugin Interface
2) By registering a AfterInitCallbacks handler:
this.AfterInitCallbacks.Add(appHost => { ... });
3) By overriding OnAfterInit() virtual method in your AppHost, e.g:
public override void OnAfterInit()
{
...
base.OnAfterInit();
}

Is there a way to ignore some entity properties when calling EdmxWriter.WriteEdmx

I am specifically using breezejs and the server code for breeze js converts the dbcontext into a form which is useable on the clientside using EdmxWriter.WriteEdmx. There are many properties which I have added JsonIgnore attributes to so that they don't get passed to the client side. However, the metadata that is generated (and passed to the clientside) from EdmxWriter.WriteEdmx still has those properties. Is there any additional attribute that I can add to those properties that I want ignored so that they are ignored by EdmxWriter.WriteEdmx? Or, would I need to make a separate method so as not to have any other unintended side effects.
You can sub-class your DbContext with a more restrictive variant that you use solely for metadata generation. You can continue to use your base context for persistence purposes.
The DocCode sample illustrates this technique with its NorthwindMetadataContext which hides the UserSessionId property from the metadata.
It's just a few extra lines of code that do the trick.
public class NorthwindMetadataContext : NorthwindContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Hide from clients
modelBuilder.Entity<Customer>().Ignore(t => t.CustomerID_OLD);
// Ignore UserSessionId in metadata (but keep it in base DbContext)
modelBuilder.Entity<Customer>().Ignore(t => t.UserSessionId);
modelBuilder.Entity<Employee>().Ignore(t => t.UserSessionId);
modelBuilder.Entity<Order>().Ignore(t => t.UserSessionId);
// ... more of the same ...
}
}
The Web API controller delegates to the NorthwindRepository where you'll see that the Metadata property gets metadata from the NorthwindMetadataContext while the other repository members reference an EFContextProvider for the full NorthwindContext.
public class NorthwindRepository
{
public NorthwindRepository()
{
_contextProvider = new EFContextProvider<NorthwindContext>();
}
public string Metadata
{
get
{
// Returns metadata from a dedicated DbContext that is different from
// the DbContext used for other operations
// See NorthwindMetadataContext for more about the scenario behind this.
var metaContextProvider = new EFContextProvider<NorthwindMetadataContext>();
return metaContextProvider.Metadata();
}
}
public SaveResult SaveChanges(JObject saveBundle)
{
PrepareSaveGuard();
return _contextProvider.SaveChanges(saveBundle);
}
public IQueryable<Category> Categories {
get { return Context.Categories; }
}
// ... more members ...
}
Pretty clever, eh?
Just remember that the UserSessionId is still on the server-side class model and could be set by a rogue client's saveChanges requests. DocCode guards against that risk in its SaveChanges validation processing.
You can sub-class your DbContext with a more restrictive variant that you use solely for metadata generation. You can continue to use your base context for persistence purposes.
The DocCode sample illustrates this technique with its NorthwindMetadataContext which hides the UserSessionId property from the metadata.
It's just a few extra lines of code that do the trick.
The Web API controller delegates to the NorthwindRepository where you'll see that the Metadata property gets metadata from the NorthwindMetadataContext while the other repository members reference an EFContextProvider for the full NorthwindContext.
Pretty clever, eh?
If you use the [NotMapped] attribute on a property, then it should be ignored by the EDMX process.

Is it possible to create an orchard autoroute using contents of a custom type property?

I have an Orchard cms module with some additional Content types set up and have added an AutoRoute component via code.
Everything works perfectly, however I am not happy with the default permalink pattern.
What I am trying to do is add a custom pattern and use one of the public properties in my content type. In my case the custom type has a public property called ClubName and I would like that to be used (It makes more sense from a routing perspective).
The Orchard part class name is called TrackPart.
I have tried {Content.TrackPart.ClubName}, {Content.Track.ClubName}, {ContentItem.TrackPart.ClubName},{Content.TrackPart.ClubName} and various other variations but nothing seems to be working.
I am really new to Orchard so there is a high chance I am missing something simple.
Any help would be greatly appreciated.
In response to feedback from #Bertrand-le-roy I created my own token by copying an example token. I can now get see the token in the drop down menu and select it. However the route pattern is still not working.
I can only assume that I have misunderstood the Evaluate() function's context.For usage. It looks like I am not getting the data I need
Here is what I have so far.
public class TrackPartTokens : ITokenProvider {
private readonly IContentManager _contentManager;
public TrackPartTokens(IContentManager contentManager) {
_contentManager = contentManager;
}
public Localizer T { get; set; }
public void Describe(dynamic context) {
context.For("Track", T("Track"), T("Tokens for Track"))
.Token("ClubName", T("ClubName"), T("The name of the club."))
;
}
public void Evaluate(dynamic context) {
context.For<TrackPart>("Track")
.Token("ClubName", (Func<TrackPart, object>)(field => field.ClubName))
.Chain("ClubName", "ClubName", (Func<TrackPart, object>)(field =>field.ClubName))
;
}</code>
The above code was based on the DateTimeField token inside the Orchard.Fields module.
context.For("DateTimeField")
.Token("Date", (Func)(field => field.DateTime))
.Chain("Date", "Date", (Func)(field => field.DateTime));
I had the same issue.
After some troubleshooting I managed to get the autoroute working by changing my implementaion to the following (adapted to your example, note that your setup might require some changes to the linq-function):
In your tokens-class:
First add a using System.Linq statement.
Then change your Evaluate implementation to the following:
context.For<IContent>("Content")
.Token("ClubName", (Func<IContent>, object>)(content =>
content.ContentItem.Parts.OfType<TrackPart>().First().ClubName));
Make sure your AutoroutePart settings in Migrations.cs uses the Content-prefix. Like:
.WithPart("AutoroutePart", partBuilder =>
partBuilder
.WithSetting("AutorouteSettings.AllowCustomPattern", "true")
.WithSetting("AutorouteSettings.AutomaticAdjustmentOnEdit", "false")
.WithSetting("AutorouteSettings.PatternDefinitions",
#"[{Name:'Track', Pattern:'{Content.ClubName}',
Description:'Your description'}]")
.WithSetting("AutorouteSettings.DefaultPatternIndex", "0"))
There seems to be some problems with the TokenManager-class in Orchard source that only allows the target-parameter to equal "Content" in order for the call: _data.TryGetValue(target, out value) to work (TokenManager.cs, line 67). I have tried a number of different setups but the _data-dictionary always only contain the "Content" key.
You'll have to make your own token. It's really easy. Copy a working example.

EF 5 Re-Use entity configuration

I'm trying to re-use some of the model configurations on several entities that implements a interface.
Check this code:
public static void ConfigureAsAuditable<T>(this EntityTypeConfiguration<T> thisRef)
where T : class, IAuditable
{
thisRef.Property(x => x.CreatedOn)
.HasColumnName("utctimestamp")
.IsRequired();
thisRef.Property(x => x.LastUpdate)
.HasColumnName("utclastchanged")
.IsRequired();
} // ConfigureAsAuditable
as you can see I'm trying to call the extension method "ConfigureAsAuditable" on my onmodelcreating method like this:
EntityTypeConfiguration<Account> conf = null;
conf = modelBuilder.Entity<Account>();
conf.ToTable("dbo.taccount");
conf.ConfigureAsAuditable();
When debugging i get this exception:
The property 'CreatedOn' is not a declared property on type
'Account'. Verify that the property has not been explicitly excluded
from the model by using the Ignore method or NotMappedAttribute data
annotation. Make sure that it is a valid primitive property.
Thanks in advance :)
PD:
I'm using EF 5-rc, VS 2011 and .NET Framework 4.5
I think a better approach would be to implement your own derived version of EntityTypeConfiguration. For example:
public class MyAuditableConfigurationEntityType<T> : EntityTypeConfiguration<T>
where T : class, IAuditable{
public bool IsAuditable{get;set;}
}
Then, when building your model, use that new type:
var accountConfiguration = new MyAuditableConfigurationEntityType<Account>();
accountConfiguration.IsAuditable = true; // or whatever you need to set
accountConfiguration.(HasKey/Ignore/ToTable/Whatever)
modelBuilder.Configurations.Add(accountConfiguration);

Resources