Ok, I'm getting an IllegalArgumentException at a point where it shouldn't.
I have a custom extension of Account that is saved using the AccountManager:
// Method inside a custom extension of Account
public boolean save(AccountManager manager) {
removeAll(manager);
boolean result = manager.addAccountExplicitly(this, null, toBundle());
manager.setUserData(this, KEY_1, value1);
manager.setUserData(this, KEY_2, value2);
manager.setUserData(this, KEY_3, value3);
return result;
}
The keys are constant String values but app still throws:
java.lang.IllegalArgumentException: key is null
I have to say that I'm only attaching the user data in this fashion because using:
manager.addAccountExplicitly(this, null, toBundle());
didn't seem to attach the values. Do the keys require a special name pattern?
Anybody had this problem before?
Update:
It gets thrown inside the manager.setUserData() which looks like this (Android code):
public void setUserData(final Account account, final String key, final String value) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
try {
mService.setUserData(account, key, value);
} catch (RemoteException e) {
// won't ever happen
throw new RuntimeException(e);
}
}
When I "walk" into this method with eclipse I get this in the debug perspective:
The values aren't null >o<
Ok, after further research into android's AccountManager I did not find a way to make it work like I was trying but I found a solution.
Instead of saving the details as an user data bundle I save them as authToken values using the key as the authTokenType like this:
public boolean save(AccountManager manager) {
removeAll(manager);
boolean result = manager.addAccountExplicitly(this, null, toBundle());
manager.setAuthToken(this, KEY_1, value1);
manager.setAuthToken(this, KEY_2, value2);
manager.setAuthToken(this, KEY_3, value3);
return result;
}
And then retrieving the values like this:
value1 = manager.peekAuthToken(account, KEY_1);
I'm still not sure if this is the way to store data for an Account but it's the only one I've managed to make work so far.
Related
I am currently working over CSV exports. I am fetching header from properties file with below code -
String[] csvHeader = exportables.get(0).getCSVHeaderMap(currentUser).keySet().stream().
map(s ->messageSource.getMessage("report."+s, null, locale)).toArray(String[]::new);
The above code works well. But i need to find a way to handle exception and also fetch data from another file, if it is not found in above file. I am expecting to use somewhat below code -
try{
exportables.get(0).getCSVHeaderMap(currentUser).keySet().stream().
map(s ->messageSource.getMessage("report."+s, null, locale)).toArray(String[]::new);
}catch(NoSuchMessageException e){
// code to work over lacking properties
}
I want to catch the 's' element in catch block (or in other good way). So that i can fetch it from another file and also add its return to current csvHeader.
One way is to make for each element a try catch block like:
exportables.get(0).getCSVHeaderMap(currentUser).keySet().stream().
map(s -> {
String result;//Put the class to which you map
try{
result = messageSource.getMessage("report."+s, null, locale);
}catch(NoSuchMessageException e){
// code to work over lacking properties here you have access to s
}
return result;
}
).toArray(String[]::new);
Another solution will be to check for specific problems and then there is no need to catch exceptions. For example if s is null and then you want to get the data from another place:
exportables.get(0).getCSVHeaderMap(currentUser).keySet().stream().
map(s -> {
String result;//Put the class to which you map
if(null == s)// Some condition that you want to check.
{
//get info from another place
//result = ....
}
else
{
result = messageSource.getMessage("report."+s, null, locale);
}
return result;
}
).toArray(String[]::new);
I have written a Java application that searches Active directory via LDAP for user information. I have a list of instances of custom Person class that is passed in. In it I have either DN or email defined. I am modifying the search criteria accordingly. Here is the code:
for (Person person : members) {
boolean ready = false;
String filter = getConfig().getUserSearchFilter();
// (&(|(objectclass=user)(objectclass=person)(objectclass=inetOrgPerson)(objectclass=organizationalPerson)))
String base = person.getDistinguishedName();
if (base != null && !base.isEmpty()) {
ready = true;
} else if (person.getEmail() != null) {
base = getConfig().getMemberSearchBase();
// ou=Users,ou=Managed,dc=division,dc=company,dc=com
String mail = person.getEmail();
StringBuilder filterBuilder = new StringBuilder(filter);
int pIdx = filterBuilder.lastIndexOf(")");
filterBuilder.insert(pIdx, "(|(mail=" + mail + ")(x-personalmail=" + mail + "))");
filter = filterBuilder.toString();
LOG.debug("New value of a filter = {}", filter);
ready = true;
}
if (ready) {
try {
NamingEnumeration<SearchResult> search = getContext().search(base, filter, searchControls);
...
} catch (NamingException nex) {
throw new IOException(nex);
}
} else {
LOG.error("Incorrect search criteria for user {} of group {}. Person skipped", person.getName(), this.group.getName());
}
}
Code is working without errors, but when DN is specified it does find a person, but when email is defined it finds nothing.
However, If I copy generated filter string and pass it to ldapsearch command in a form of:
ldapsearch -LLL -x -H ldaps://my.ldap.server.com -D 'svc-acct#corp-dev.company.com' -W -b "ou=Users,ou=Managed,dc=division,dc=company,dc=com" '(&(|(objectclass=user)(objectclass=person)(objectclass=inetOrgPerson)(objectclass=organizationalPerson))(|(mail=person#domain.com)(x-personalmail=person#domain.com)))'
It does find this person perfectly.
Did anyone faced similar problem? Do you see any flaws in my code?
Please, do help me.
I did find the cause of my problem.
In the search control I had scope defined as OBJECT_SCOPE.
It does work when you are specifying DN, but with the search per one of the fields it fails finding the object.
I changed the scope to SUBTREE_SCOPE and everything started working as expected.
According to the official documentation Update API - Upserts one can use scripted_upsert in order to handle update (for existing document) or insert (for new document) form within the script. The thing is they never show how the script should look to do that. The Java - Update API Doesn't have any information on the ScriptUpsert uses.
This is the code I'm using:
//My function to build and use the upsert
public void scriptedUpsert(String key, String parent, String scriptSource, Map<String, ? extends Object> parameters) {
Script script = new Script(scriptSource, ScriptType.INLINE, null, parameters);
UpdateRequest request = new UpdateRequest(index, type, key);
request.scriptedUpsert(true);
request.script(script);
if (parent != null) {
request.parent(parent);
}
this.bulkProcessor.add(request);
}
//A test call to validate the function
String scriptSource = "if (!ctx._source.hasProperty(\"numbers\")) {ctx._source.numbers=[]}";
Map<String, List<Integer>> parameters = new HashMap<>();
List<Integer> numbers = new LinkedList<>();
numbers.add(100);
parameters.put("numbers", numbers);
bulk.scriptedUpsert("testUser", null, scriptSource, parameters);
And I'm getting the following exception when "testUser" documents doesn't exists:
DocumentMissingException[[user][testUser]: document missing
How can I make the scriptUpsert work from the Java code?
This is how a scripted_upsert command should look like (and its script):
POST /sessions/session/1/_update
{
"scripted_upsert": true,
"script": {
"inline": "if (ctx.op == \"create\") ctx._source.numbers = newNumbers; else ctx._source.numbers += updatedNumbers",
"params": {
"newNumbers": [1,2,3],
"updatedNumbers": [55]
}
},
"upsert": {}
}
If you call the above command and the index doesn't exist, it will create it, together with the newNumbers values in the new documents. If you call again the exact same command the numbers values will become 1,2,3,55.
And in your case you are missing "upsert": {} part.
As Andrei suggested I was missing the upsert part, changing the function to:
public void scriptedUpsert(String key, String parent, String scriptSource, Map<String, ? extends Object> parameters) {
Script script = new Script(scriptSource, ScriptType.INLINE, null, parameters);
UpdateRequest request = new UpdateRequest(index, type, key);
request.scriptedUpsert(true);
request.script(script);
request.upsert("{}"); // <--- The change
if (parent != null) {
request.parent(parent);
}
this.bulkProcessor.add(request);
}
Fix it.
I am using UnboundID-LDAPSDK (2.3.8) to change the user's photo in our Microsoft Active Directory.
LDAPConnection ldap = null;
try {
ldap = new LDAPConnection("domain-srv", 389, "CN=admin,OU=Users,OU=ADM,DC=domain,DC=local", "password");
SearchResult sr = ldap.search("DC=domain,DC=local", SearchScope.SUB, "(sAMAccountName=" + getUser().getUsername() + ")");
if (sr.getEntryCount() == 1) {
SearchResultEntry entry = sr.getSearchEntries().get(0);
entry.setAttribute("thumbnailPhoto", getUser().getPhotoAsByteArray());
ldap.close();
return true;
} else
return false;
} catch (LDAPException e) {
e.printStackTrace();
}
But I get a java.lang.UnsupportedOperationException.
The documentation for setAttribute states:
Throws an UnsupportedOperationException to indicate that this is a
read-only entry.
I also tried to change the postalCode but I get the same exception.
Changing those attributes should be possible, because I can change them with jXplorer.
Do I have to enable a write-mode somehow?
Thank you
The SearchResultEntry object extends ReadOnlyEntry and is therefore immutable. But even if it weren't, merely calling entry.setAttribute would have no effect on the data in the server. You have to use a modify operation for that.
To do that, you'd need something like:
ModifyRequest modifyRequest = new ModifyRequest(entry.getDN(),
new Modification(ModificationType.REPLACE,
"thumbnailPhoto", getUser().getPhotoAsByteArray());
ldap.modify(modifyRequest);
Also, you should put the call to ldap.close() in a finally block because as the code is written now, you're only closing the connection if the search is successful and returns exactly one entry, but not if the search fails, doesn't match any entries, or the attempt to perform the modify fails.
I still can't work with GAE's keys/ids. I keep getting the error: No entity was found matching the key: Key(Medewerker(5201690726760448)). The entities exist in the datastore, I checked this multiple times.
I'm trying to just simply get an user object with a certain ID. In my servlet I have the following code:
Long userId = Long.parseLong(req.getParameter("user"));
User user = userDao.getUser(userId);
The above code brings up the error. In userDaoOfyImpl.java I have the following method 'getUser':
public Gebruiker getGebruiker(Long id) {
Gebruiker result = null;
Gebruiker leerling = (Gebruiker) ofy.get(Leerling.class, id);
Gebruiker medewerker = (Gebruiker) ofy.get(Medewerker.class, id);
Gebruiker stagebedrijf = (Gebruiker)ofy.get(StageBedrijf.class, id);
//Gebruiker instantie returnen
if(leerling != null) {
result = leerling;
} else if(medewerker != null) {
result = medewerker;
} else if(stagebedrijf != null) {
result = stagebedrijf;
}
return result;
}
The variables are dutch but I think you guys know the idea. The above method searches in different classes looking for a user that matches the ID and then returns it.
The problem is I get the error shown above and I'm really getting frustrated, what am I doing wrong guys? Is it the method or the way I use ID's or...?
Thanks in advance!
here you can read for the get method:
Throws: NotFoundException - if the key does not exist in the datastore
use
Gebruiker leerling = (Gebruiker) ofy.find(Leerling.class, id);
the find method doesn't throws NotFoundException when the key doesn't exist but null.