I want to access the JSFUnit FacesContext before I create the JSFSession object. The reason for this is I would like to set a managed bean value before any request/response processing is done. I use this value in a filter.
I am not sure exactly what do you want to accomplish, however, if you want to set values before any request will be processed, use WebClientSpec with setInitialRequestStrategy.
For example, you can use FormAuthenticationStrategy:
WebClientSpec wcSpec = new WebClientSpec("/secure.jsp");
FormAuthenticationStrategy formStrategy = new FormAuthenticationStrategy("user", "password");
formStrategy.setSubmitComponent("login_button");
wcSpec.setInitialRequestStrategy(formStrategy);
JSFSession jsfSession = new JSFSession(wcSpec);
or define your own custom request strategy that implements InitialRequestStrategy.
See FormAuthenticationStrategy code and create something similar to it.
Related
This question is on best practice and if possible.
I need to know if I can dynamically change the base of ldap context source within code?
With my ldap bean wired with the following
<ldap:context-source
url="ldap://<url>"
base="dc=example,dc=local"
username="<user>#example.local"
password="<pass>"
/>
can I in code change the context source to another base depending on a given dynamically changing parameter?
For instance if i want to change base to dc=example2,dc=local .
If I was programmatically setting up LdapContextSource this would be no problem.
So this was simpler and easier than I thought.
All i had to do was go ahead and create
LdapContextSource ctxSrc = new LdapContextSource();
ctxSrc.setUrl("ldap://<url>");
ctxSrc.setBase("dc=example,dc=local");
ctxSrc.setUserDn("<user>#example.local");
ctxSrc.setPassword("<pass>");
ctxSrc.afterPropertiesSet(); // this method should be called.
LdapTemplate tmpl = new LdapTemplate(ctxSrc);
setLdapTemplate(tmpl);
and base my LdapContextSource values on the properties that in my case is a dynamic source.
I was thinking that there was something more Spring like to do .
Is there a way we can use ObjectContext with DbContext's ModelBuilder? We don't want to use POCO because we have customized property code that does not modify entire object in update, but only update modified properties. Also we have lots of serialisation and auditing code that uses EntityObject.
Since poco does create a proxy with EntityObject, we want our classes to be derived from EntityObject. We don't want proxy. We also heavily use CreateSourceQuery. The only problem is EDMX file and its big connection string syntax web.config.
Is there any way I can get rid of EDMX file? It will be useful as we can dynamically compile new class based on reverse engineering database.
I would also like to use DbContext with EntityObject instead of poco.
Internal Logic
Access Modified Properties in Save Changes which is available in ObjectStateEntry and Save them onto Audit with Old and New Values
Most of times we need to only check for Any condition on Navigation Property for example
User.EmailAddresses.CreateSourceQuery()
.Any( x=> x.EmailAddress == givenAddress);
Access Property Attributes, such as XmlIgnore etc, we rely heavily on attributes defined on the properties.
A proxy for a POCO is a dynamically created class which derives from (inherits) a POCO. It adds functionality previously found in EntityObject, namely lazy loading and change tracking, as long as a POCO meets requirements. A POCO or its proxy does not contain an EntityObject as the question suggests, but rather a proxy contains functionality of EntityObject. You cannot (AFAIK) use ModelBuilder with EntityObject derivatives and you cannot get to an underlying EntityObject from a POCO or a proxy, since there isn't one as such.
I don't know what features of ObjectContext does your existing serialisation and auditing code use, but you can get to ObjectContext from a DbContext by casting a DbContext to a IObjectContextAdapter and accessing IObjectContextAdapter.ObjectContext property.
EDIT:
1. Access Modified Properties in Save Changes which is available in ObjectStateEntry and Save them onto Audit with Old and New Values
You can achieve this with POCOs by using DbContext.ChangeTracker. First you call DbContext.ChangeTracker.DetectChanges to detect the changes (if you use proxies this is not needed, but can't hurt) and then you use DbCotnext.Entries.Where(e => e.State != EntityState.Unchanged && e.State != EntityState.Detached) to get DbEntityEntry list of changed entities for auditing. Each DbEntityEntry has OriginalValues and CurrentValues and the actual Entity is in property Entity.
You also have access to ObjectStateEntry, see below.
2. Most of times we need to only check for Any condition on Navigation Property for example:
User.EmailAddresses.CreateSourceQuery().Any( x=> x.EmailAddress == givenAddress);
You can use CreateSourceQuery() with DbContext by utilizing IObjectContextAdapter as described previously. When you have ObjectContext you can get to the source query for a related end like this:
public static class DbContextUtils
{
public static ObjectQuery<TMember> CreateSourceQuery<TEntity, TMember>(this IObjectContextAdapter adapter, TEntity entity, Expression<Func<TEntity, ICollection<TMember>>> memberSelector) where TMember : class
{
var objectStateManager = adapter.ObjectContext.ObjectStateManager;
var objectStateEntry = objectStateManager.GetObjectStateEntry(entity);
var relationshipManager = objectStateManager.GetRelationshipManager(entity);
var entityType = (EntityType)objectStateEntry.EntitySet.ElementType;
var navigationProperty = entityType.NavigationProperties[(memberSelector.Body as MemberExpression).Member.Name];
var relatedEnd = relationshipManager.GetRelatedEnd(navigationProperty.RelationshipType.FullName, navigationProperty.ToEndMember.Name);
return ((EntityCollection<TMember>)relatedEnd).CreateSourceQuery();
}
}
This method uses no dynamic code and is strongly typed since it uses expressions. You use it like this:
myDbContext.CreateSourceQuery(invoice, i => i.details);
I have implemented Autoconverter (with forceSelection=false) in maintainance screen.
To edit existing record, User will select ID from Autocomplete list.
To add new record, user will enter new ID in same box.
In converter, Application will try to search record in DB using ID.
If not found, New empty object is created with supplied ID and to avoid duplications, this object is added to array list maintained in Converter.
This works as expected on single browser session. but while testing with multiple browser, I found that Array list is shared across all instances.
I am not sure whether approach I have taken is right? if not can you please suggest me an alternative approach.
private List<SchoolMasterDetails> schoolMasterDetailsDB = new ArrayList<SchoolMasterDetails>();
#Override
public Object getAsObject(FacesContext facesContext, UIComponent component, String submittedValue) {
SchoolMasterDetails selectedObject = null;
System.out.println("getAsObject ==> Entering.");
System.out.println("getAsObject ==> '" + submittedValue + "'");
if (!submittedValue.trim().equals("")) {
selectedObject = (SchoolMasterDetails) getMasterService().getSchoolbyCode(submittedValue);
if (selectedObject == null) {
// search Object on localDB
for (SchoolMasterDetails p : schoolMasterDetailsDB) {
if (p.getSchoolCode().equalsIgnoreCase(submittedValue.trim())) {
System.out.println("getAsObject from ArrayList ==> " + p);
return p; // return selectedObject from list of created objects
}
}
System.out.println("getAsObject ==> selectedObject is null, Hence Creating new Object");
selectedObject = new SchoolMasterDetails();
selectedObject.setSchoolCode(submittedValue.trim());
selectedObject.setSchoolName("TEST TEST TEST");
schoolMasterDetailsDB.add(selectedObject);
}
else {
System.out.println("getAsObject from Database ==> " + selectedObject);
}
}
System.out.println("getAsObject ==> " + selectedObject);
}
System.out.println("getAsObject ==> Exiting.");
return selectedObject;
}
Regards,
Shirish
As far as I understand this (still learning myself), a converter fulfills exactly one purpose: It prepares your custom objects to be used in the views (getAsString) and translates Strings back into objects (getAsObject). It will be used whenever an input (a radio list, textfield, autocomplete) is tied to a variable in a backing bean that is of the type of your custom object. It is in your freedom to decide what String should be used to represent your object and how you use this String in return to look up objects.
With this in mind I would not use a converter to store a local list of objects, nor let it handle the creation process itself. Instead, I'd assume there is a backing bean somewhere, which holds your data objects and takes care of all your logic. This bean can have a list of, say, schoolMasters that can be queried for the objects it contains (similar to what your doing). You could then either implement the lookup there in a way that it handles the not-found case and always returns a valid object (which may be a new one), or you could catch the not-found-case in the converter and then trigger a createNew() from the bean to get a new instance.
IMHO this separates the management of the instances more clearly from the translating purpose of your converter. Also, from your code, it seems like you have two places to look up objects - via getMasterService() (a local method?) and inside your stored ArrayList. I don't quite get this...
As for your problem with the browsers sharing an instance: This sounds like a scope issue. If your backing bean, which is supposed to store and manage your data, is in application scope then the same set of data will be available as long as the application runs. This data will be available across browsers and also across users.
On the other hand, if you put the bean in session scope, each session will create its own instance of the bean and store unique data. Similarly, view scoped beans live as long as a single view and request beans are trashed and regenerate for each http request. You can read more here: How to choose the right scope
The answers there talk about beans (which is where your data usually lives). I'm not sure about converters, I see them as classes that are available application wide, so that each session and view can use them for translation - if you maintain a list there, it may well be globally available.
I have used many JSON object in applicationScope, sessionScope, and viewScope to track related data. Writing and reading these in SSJS is very simple:`
//Create a app scope variable
applicationScope.put("myvarname", {p1:"part 1", p2:"part2"});
// read and use the app scope variable ...
var myvar = applicationScope.get("myvarname");
//Work with parts as myvar.p1, myvar.p2, etc...
In the Java code I have been writing I have learned to read these variables which were written using SSJS using the com.ibm.jscript.std.ObjectObject package with code like this:
ObjectObject myvar = (ObjectObject) ExtLibUtil
.getApplicationScope().get(dbkey);
FBSValue localFBS = myvar.get("p1");
String myp1 = localFBS.stringValue();
localFBS = myvar.get("p2");
String myp2 = localFBS.stringValue();
Now, of course, I want to write a new entry using the Java Bean that can then be read by SSJS and other Java Beans in the same manner. I managed to write to the scope using a Map and a Hashtable, but these crash the logic when trying to read using the ObjectObject.
So, how would I go about building a new entry in the scope using the ObjectObject and/or FBSValue packages? I cannot find how to create a new FBSValue that can then be added to an ObjectObject. I am sure it is a simple thing a Newbs like me has missed.
/Newbs
You can construct an empty ObjectObject, populate it with FBSValues, and just put it directly into the scope Map:
ObjectObject myvar = new ObjectObject();
try {
myvar.put("p1", FBSUtility.wrap("part 1"));
myvar.put("p2", FBSUtility.wrap("part 2"));
} catch (InterpretException e) {
e.printStackTrace();
}
Map<String, Object> applicationScope = ExtLibUtil.getApplicationScope();
applicationScope.put("myvarname", myvar);
When retrieving it later (as in the examples you provided), SSJS will see it as JSON, Java will see it exactly as it was stored.
If you need to store deeper hierarchies, you can put instances of ArrayObject and ObjectObject inside an ObjectObject in addition to primitives, so, just like JSON itself, you can nest these as deep as you need.
Just be sure to only include true JSON (strings, numbers, booleans, arrays, objects) if you'll be storing it anywhere higher than the requestScope; specifically, FunctionObject does not implement Serializable, so JSON is safe to store, JavaScript is not. Strictly speaking, this only becomes toxic when stored in the viewScope in 8.5.2 and 8.5.3 (and even then, only when the application's persistence option is not set to keep all pages in memory). But if IBM ever implements cluster support, then all objects stored in sessionScope and applicationScope will need to be serializable to allow for inter-server state transport... so, in the interest of future-proofing the design, it's wise to hold to this principle for anything stored longer than the duration of a single request.
I have a customer SecureSocketFactory set to be used by Axis when making an https connection using the following property:
AxisProperties.setProperty("axis.socketSecureFactory",
"com.metavante.csp.model.manager.mobilepayments.MonitiseSSLSocketFactory");
When this class is instantiated by Axis, the constructor with a Hashtable (attributes) is called. I see the timeout attribute is set in this table. Is there anyway to set more values in this?
I would like to be able to configure the Socket Factory on a per-instance scenario instead of globally by using static or system properties.
Edit: I found out these attributes are actually the HttpSender (BasicHandler) options. I still am unable to set these dynamically though.
I figured out a way around the problem. In my code where I wanted to set the property I use:
serviceLocator.getEngine().setOption(USE_CERT_PROPERTY, new Boolean(true));
where getEngine returns the AxisEngine in use. Then in the socket factory I can:
Boolean useSMS = (Boolean) MessageContext.getCurrentContext().getProperty(OtherClass.USE_CERT_PROPERTY);
I could set the object to whatever, maybe I'll go with the certificate name I needed. Hope this helps someone.
You can retrieve the SocketFactory instance and then change or add attributes, if you are interested in modify SocketFactory behavior. But if you do this, you also should inject the HashTable attribute (with the timeout). I think there is not a final and pretty solution.
AxisProperties.setProperty("org.apache.axis.components.net.SecureSocketFactory", MyAxisSocketFactory.class.getName());
MyAxisSocketFactory factory = (MyAxisSocketFactory) SocketFactoryFactory.getFactory("https", myHashTableParams);
factory.setMyStuff();
After this code, the instance of SocketFactory will be created and configured, and ready to use in web services, or whatever ^_^