In contrast to attributes with the persistence type set to property that are persisted in a database, Dynamic Attributes have non-persistent values
SAP Hybris Commerce allows for a non-persistent kind of attribute referred to as a jalo attribute or jalo-only attribute.
Jalo attributes are deprecated and replaced by Dynamic Attributes.
I still see Hybris still using both.
So,What is the difference between of each?
What is the purpose of each?
Thanks
Actually half of the answer is in your question, Both Jalo and Dynamic attributes are used to create non-persisted attributes for items in Hybris.
But why do we need non-persisted attribute?
As you may know Items class in Hybris are generated using ant command so there is no way to add business logic manually to the item (because every time i run ant command a new item will be generated and my logic will be erased too)
I will give you an example :
//generated item
class PersonModel {
//persisted attributes
String firstname;
String lastName;
//non-persisted attribute = calculated attribute
String getFullName() {
return firstname + " " + lastname;
}
}
We all agree that fullName should not be persisted in the database, so let's assume that getFullName is added manually, then as i explained before if we run ant clean all command PersonModel will be re-generated again and getFullName() will be erased too.
So this what Jalo attribute created for, actually Jalo items are generated only once and will never be removed (it can be removed manually) so we can add all calculated attributes in Jalo item without fear of being erased.
//generated item is going to
//be re-generated after each ant clean all
class PersonModel {
//persisted attributes
String firstname;
String lastName;
}
//Jalo item will be generated once
//and will never be removed after that
class PersonJalo {
//non-persisted attribute = calculated attribute
String getFullName() {
return firstname + " " + lastname;
}
}
Jalo attribute is deprecated now and replaced by dynamic attribute, so we should never use jalo any more and use dynamic attribute instead.
Related
I want to know if it is a way to trigger my Validation Code just for impex. What I mean is that my Code should validate a new Product created through Impex (not through backoffice). Here is my Code:
#Override
public void onValidate(final Object o, final InterceptorContext ctx) throws InterceptorException
if (o instanceof ProductModel)
{
final ProductModel product = (ProductModel) o;
if (ctx.isNew(product))
{
final String manufacturerName = enumerationService.getEnumerationName(product.getManufacturerName()); // if ManufacturerName is Null enumerationService throw "Parameter plainEnum must not be null!"
final String code = product.getCode().toString();
final String manufacturerProductId = product.getManufacturerProductId();
final int a = productLookupService.getProduct(code, manufacturerName, manufacturerProductId);
switch (a)
{
case 1:
throw new InterceptorException("Product already in ProductLookup");
case 2:
throw new InterceptorException(
"There are more than one product with the same " + code + " number in ProductLookup !");
default:
}
}
}
My Problem is that in BackOffice when I create a new Product I don´t have manufacturerName and manufacturerProductId fields.
Thanks! and sorry if I said something wrong, I am new in this :)
You said that "In BackOffice when i create a new Product i don´t have manufacturerName and manufacturerProductId fields".
This can also be the case for Impex. Most probably the impex you are using is specifying those two attributes now and that is why there is no problem.
If you want, you can make this two attributes mandatory and then nobody will be able to create a product without specifying the manufacturerName ad the manufacturerProductId.
I also believe that the backOffice will update to also include these two attributes during creation since they are mandatory.
You can specify that an attribute is mandatory in your {extensionName}-items.xml(under your type definition) using the optional flag like below:
<attribute qualifier="manufacturerProductId" type="String">
<persistence type="property"/>
<modifiers optional="false"/>
</attribute>
If these two attributes are not mandatory, you have to consider the case when a product will be created without having them(like your current backOffice situation).
However your Interceptor should take into consideration both cases (when you have these attributes specified during creation and when you don't)
Because of this you can edit your code to verify whether this two attributes are null or not before using them. You can add this right before trying to get the manufacturerName:
if (product.getManufacturerName() == null || product.getManufacturerProductId() == null) {
return;
}
I'm working on the LDAP overlay of MitreID Connect project and everthing is working greatly:
Authentication
Retrieving attributes from LDAP Directory
The problem I have now, is how to retrieve operational attributes in LDAP directory.
I'm not good with Spring development, but I found some documentation which treat this sub, but I'm not able to make it work.
Here's what I found:
Retrieving operational attributes
Ldap Server maintains many operational attributes internally. Example entryUUID is an operational attribute assigns the Universally Unique Identifier (UUID) to the entry. The createTimestamp, modifyTimestamp are also operational attributes assigned to the entry on create or update. These operational attributes does not belong to an object class and hence they were not returned as part of your search or lookup. You need to explicitly request them by their name in your search or build the custom AttributeMapper implementation with matching attribute names.
Now let’s try to retrieve the entryUUID, first you need to build the search controls like this,
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setReturningObjFlag(false);
controls.setReturningAttributes(new String[]{"entryUUID"});
Once you have search control then it’s simply calling search method just like retrieving any other attributes.
ldapTemplate.search("baseName", "(objectclass=person)", controls, new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs) throws NamingException {
Attribute attrUuid = attrs.get("entryUUID");
return attrUuid;
}});
Here is another way to do the same using ContextMapper,
ldapTemplate.search("baseName","(objectclass=person)", 1, new String[]{"entryUUID"},
new ContextMapper(){
public Object mapFromContext(Object ctx) {
DirContextAdapter context = (DirContextAdapter)ctx;
return context.getStringAttributes("entryUUID");
}
});
Let’s add the filter based off of operational attributes like below,
OrFilter orFilter = new OrFilter();
orFilter.or(new GreaterThanOrEqualsFilter("createTimestamp", "YYYYMMDDHHMMSSZ"));
orFilter.or(new LessThanOrEqualsFilter("modifyTimestamp", "YYYYMMDDHHMMSSZ"));
Now call the above search with the filter
ldapTemplate.search("baseName", orFilter.encode(), controls, new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs) throws NamingException {
Attribute attrUuid = attrs.get("entryUUID");
return attrUuid;
}});
I am using JHipster 3.3. In the generated "entity"-dialog.html, I noticed the tag jhi-alert-error element will display server validation error so for example if a field is mandatory as specified in entity JPA class like
#NotNull
private String name;
Then error message for that field will be returned after clicking the Submit button if value of the field is empty.
So questions:
How is jhi-alert-error implemented? I can't seem to see its implementation
I tried tweaking JPA annotation to make a field unique BUT this time no error message will be displayed in jhi-alert-error if I break the unique constraint by adding 2 records having the same value for the field,
E.g.
// note 'unique=true' below
#NotNull
#Column(name = "name", unique=true)
private String name;
or
#Table(name="Module", uniqueConstraints = #UniqueConstraint(columnNames = "Name"))
public Class Module implements Serializable { ...
So how would I go about implementing my own server side form validation so error messages will be displayed in jhi-alert-error when the unique constraint of a field is broken after clicking the Submit button?
Thanks in advance,
I'm using a slightly older version of jhipster (2.26), so there could be some differences in the code. To answer your first question the jhi-alert-error is a custom Angular directive, have a look at the alert.directive.js file and the jhAlertError directive (should appear after the jhAlert directive). The directive expects the httpResponse.data object to be the ErrorDTO server side object.
To add custom error messages, you need to return an ErrorDTO object and the directive will display the message. To do this you need to throw an exception and ensure that the spring AOP - ExceptionTranslator is configured to catch it. If you don't want to create new custom Exceptions, you can use the CustomParameterizedException:
#RequestMapping(value = "/pizzas",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Pizza> create(#RequestBody Pizza pizza) throws URISyntaxException {
if(pizza.isDisgusting()){
throw new CustomParameterizedException("Sorry, your pizza recipe is horrible");
}
log.debug("REST request to save Pizza : {}", pizza);
if (pizza.getId() != null) {
return ResponseEntity.badRequest().header("Failure", "A new pizza cannot already have an ID").body(null);
}
Pizza result = pizzaRepository.save(pizza);
return ResponseEntity.created(new URI("/api/pizzas/" + pizza.getId())).body(result);
}
I have a business requirement to only send permissioned properties in our response payload. For instance, our response DTO may have several properties, and one of them is SSN. If the user doesn't have permissions to view the SSN then I would never want it to be in the Json response. The second requirement is that we send null values if the client has permissions to view or change the property. Because of the second requirement setting the properties that the user cannot view to null will not work. I have to still return null values.
I have a solution that will work. I create an expandoObject by reflecting through my DTO and add only the properties that I need. This is working in my tests.
I have looked at implementing ITextSerializer. I could use that and wrap my response DTO in another object that would have a list of properties to skip. Then I could roll my own SerializeToString() and SerializeToStream(). I don't really see any other ways at this point. I can't use the JsConfig and make a SerializeFn because the properties to skip would change with each request.
So I think that implementing ITextSerializer is a good option. Are there any good examples of this getting implemented? I would really like to use all the hard work that was already done in the serializer and take advantage of the great performance. I think that in an ideal world I would just need to add a check in the WriteType.WriteProperties() to look and the property is one to write, but that is internal and really, most of them are so I can't really take advantage of them.
If someone has some insight please let me know! Maybe I am making the implementation of ITextSerialzer a lot harder that it really is?
Thanks!
Pull request #359 added the property "ExcludePropertyReference" to the JsConfig and the JsConfigScope. You can now exclude references in scope like I needed to.
I would be hesitant to write my own Serializer. I would try to find solutions that you can plug in into the existing ServiceStack code. That way you will have to worry less about updating dlls and breaking changes.
One potential solution would be decorating your properties with a Custom Attributes that you could reflect upon and obscure the property values. This could be done in the Service before Serialization even happens. This would still include values that they user does not have permission to see but I would argue that if you null those properties out they won't even be serialized by JSON anyways. If you keep all the properties the same they you will keep the benefits of strong typed DTOs.
Here is some hacky code I quickly came up with to demonstrate this. I would move this into a plugin and make the reflection faster with some sort of property caching but I think you will get the idea.
Hit the url twice using the following routes to see it in action.
/test?role
/test?role=Admin (hack to pretend to be an authenticated request)
[System.AttributeUsage(System.AttributeTargets.Property)]
public class SecureProperty : System.Attribute
{
public string Role {get;set;}
public SecureProperty(string role)
{
Role = role;
}
}
[Route("/test")]
public class Test : IReturn
{
public string Name { get; set; }
[SecureProperty("Admin")]
public string SSN { get; set; }
public string SSN2 { get; set; }
public string Role {get;set;}
}
public class TestService : Service
{
public object Get(Test request)
{
// hack to demo roles.
var usersCurrentRole = request.Role;
var props = typeof(Test).GetProperties()
.Where(
prop => ((SecureProperty[])prop
.GetCustomAttributes(typeof(SecureProperty), false))
.Any(att => att.Role != usersCurrentRole)
);
var t = new Test() {
Name = "Joe",
SSN = "123-45-6789",
SSN2 = "123-45-6789" };
foreach(var p in props) {
p.SetValue(t, "xxx-xx-xxxx", null);
}
return t;
}
}
Require().StartHost("http://localhost:8080/",
configurationBuilder: host => { });
I create this demo in ScriptCS. Check it out.
I am trying to add fields to com.liferay.portal.model.User, an extra attribute using Expando. Can someone explain to me how this method is adding a field because docs don't have much description.
private void addUserCustomAttribute(long companyId, ExpandoTable userExpandoTable, String attributeName, int type) throws PortalException, SystemException {
ExpandoColumnLocalServiceUtil.getColumn(userExpandoTable.getTableId(), attributeName); //should be addColumn(long tableId, String name, int type) ???
} //and where can find type description couse i have very specific type, Map(String,Object) couse in ExpandoColumnConstants didn't see it
I have taken this from Liferay Expando Wiki's Adding User Custom Attributes.
When should I call this all? Where to put this in my project? What change is required or everything needs to be changed to call it.
Some good tutorial will be nice because it's hard to find something from 0 to end, always found only some part with no explanation.
The question is not very clear. But if you simply want to add a custom attribute for your User then you can refer to my answer here and reproduced for your reference:
Custom field for the user-entity can be created through:
Control Panel -> Portal -> Custom Fields -> User.
And programmatically can be created as follows:
user.getExpandoBridge().addAttribute("yourCustomFieldKey");
Then set the value as:
user.getExpandoBridge().setAttribute("yourCustomFieldKey", "valueForCustomField");
If your custom field is already present you can check like this:
if (user.getExpandoBridge().hasAttribute("yourCustomFieldKey")) { ... };
The data is stored in tables prefixed with "EXPANDO":
EXPANDOCOLUMN: stores the custom field key and other settings
(contains the tableId refrences)
EXPANDODATA: stores the custom field value for the key (contains the
columnId and tableId refrences)
EXPANDOTABLE: stores for which liferay entity (user) are you adding
the custom field
EXPANDOROW: stores linking information between a user and its values
(contains tableId and userId refrences)
Hope this helps.
If your custom field is multivalue, you can use this:
String customVal = "yourCustomFieldValue";
user.getExpandoBridge().setAttribute("yourCustomFieldKey", new String[] {customVal }, false);
The last parameter set to "false" avoids permission check.