Closed bjhargrave closed 17 years ago
Comment author: @bjhargrave
The UserPromptCondition class defines an inner interface: UserPromptConditionFactory which is marked protected. However the class file is public and so the inner interface is part of the public API.
// class version 46.0 (46) // access flags 1537 public abstract interface org/osgi/util/mobile/UserPromptCondition$UserPromptConditionFactory {
// compiled from: UserPromptCondition.java INNERCLASS org/osgi/util/mobile/UserPromptCondition$UserPromptConditionFactory org/osgi/util/mobile/UserPromptCondition UserPromptConditionFactory 1548
// access flags 1025 public abstract getInstance(Lorg/osgi/framework/Bundle;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/osgi/util/mobile/UserPromptCondition; }
The UserPromptCondition class must be changed to remove this inner interface.
Comment author: @bjhargrave
Also the following methods of UserPromptCondition are part of the public API and are not documented:
protected UserPromptCondition() protected static void setFactory(UserPromptConditionFactory factory) protected static UserPromptCondition unWrap(UserPromptCondition c)
These methods must either be documented or be removed from the public API (at least no longer public or protected).
Comment author: @pkriens
In this case, the interface was no necessary. The conditions were designed to use a factory approach, the implementation of ConditionalPermissionAdmin must always use the getCondition() method and the return value does not even have to extend the implementation class, the return value must implement the Condition interface only (It can even return the TRUE or FALSE instances).
Unfortunately, the test verified that the class relation, so this is also changed. the UserPromptCondition is now clean, there are no public methods outside the static getCondition method. All tests pass.
RCS file: /cvshome/build/org.osgi.test.cases.policy/src/org/osgi/test/cases/policy/tbc/UserPromptCondition/GetCondition.java,v retrieving revision 1.3 diff -u -r1.3 GetCondition.java --- src/org/osgi/test/cases/policy/tbc/UserPromptCondition/GetCondition.java 18 Nov 2005 20:20:18 -0000 1.3 +++ src/org/osgi/test/cases/policy/tbc/UserPromptCondition/GetCondition.java 7 Jul 2006 07:28:49 -0000 @ @ -99,7 +99,9 @ @ MessagesConstants.ASSERT_NOT_NULL, new String[] { "Created UserPrompt" }), condition);
tbc.assertTrue("Asserts that the returned Condition is an instanceof UserPromptCondition.",(condition instanceof UserPromptCondition));
// ### The following test is not valid. The condition does not
// have to be an instance of the UserPromptCondition
//tbc.assertTrue("Asserts that the returned Condition is an instanceof UserPromptCondition.",(condition instanceof UserPromptCondition)); } catch (Exception e) { tbc.fail(MessagesConstants.getMessage( MessagesConstants.UNEXPECTED_EXCEPTION, new String[] { @ @ -455,7 +457,10 @ @ MessagesConstants.ASSERT_NOT_NULL, new String[] { "Created UserPrompt" }), condition);
tbc.assertTrue("Asserts that the returned Condition is an instanceof UserPromptCondition.",(condition instanceof UserPromptCondition));
//### See 9.7.1, a Condition object must implement the
// Condition interface, it does not have to be an instance of
// the given implementation class.
//tbc.assertTrue("Asserts that the returned Condition is an instanceof UserPromptCondition.",(condition instanceof UserPromptCondition)); } catch (Exception e) { tbc.fail(MessagesConstants.getMessage( MessagesConstants.UNEXPECTED_EXCEPTION, new String[] {
RCS file: /cvshome/build/org.osgi.util.mobile/src/org/osgi/util/mobile/UserPromptCondition.java,v retrieving revision 1.23 diff -u -r1.23 UserPromptCondition.java --- src/org/osgi/util/mobile/UserPromptCondition.java 21 Jun 2006 17:39:27 -0000 1.23 +++ src/org/osgi/util/mobile/UserPromptCondition.java 7 Jul 2006 07:28:50 -0000 @ @ -17,255 +17,124 @ @ */ package org.osgi.util.mobile;
-import java.util.Dictionary; -import org.osgi.framework.AdminPermission; +import java.lang.reflect.; +import java.security.; + import org.osgi.framework.Bundle; -import org.osgi.service.condpermadmin.Condition; -import org.osgi.service.condpermadmin.ConditionInfo; +import org.osgi.service.condpermadmin.*;
/**
*/ -public class UserPromptCondition implements Condition {
+public class UserPromptCondition { /**
classNameProperty
property can be used extend this API. This is not/**
*/
protected static UserPromptCondition unWrap(UserPromptCondition c) {
if (c.realUserPromptCondition==null) return c;
return c.realUserPromptCondition;
static void init() {
getCondition = (Method) AccessController
.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
String className = System
.getProperty(classNameProperty);
if (className == null)
throw new NoClassDefFoundError(
classNameProperty
Class delegateClass;
delegateClass = Class.forName(className);
Method result = delegateClass.getMethod(
"getCondition",
new Class[] {Bundle.class,
ConditionInfo.class });
if (!Modifier.isStatic(result.getModifiers()))
throw new NoSuchMethodError(
"getCondition method must be static");
return result;
}
catch (Exception e) {
throw new RuntimeException(
"Cannot create UserPromptCondition " + e);
}
}
}); }
/**
*
null
.null
.
*/public static Condition getCondition(Bundle bundle,ConditionInfo conditionInfo)
{
String[] args = conditionInfo.getArgs();
if (args==null) throw new NullPointerException("args");
if (args.length!=4) throw new IllegalArgumentException("args.length=="+args.length+" (should be 4)");
if (bundle==null) throw new NullPointerException("bundle");
String levels = args[0];
String defaultLevel = args[1];
String catalogName = args[2];
String message = args[3];
if (levels==null) throw new NullPointerException("levels");
if (defaultLevel==null) throw new NullPointerException("defaultLevel");
if (catalogName==null) throw new NullPointerException("catalogName");
if (message==null) throw new NullPointerException("message");
if (factory==null) {
// the bundle implementing the UserPromptCondition has not started yet.
// Do wrapping magick.
return new UserPromptCondition(false,bundle,levels,defaultLevel,catalogName,message);
} else {
// there is already a factory, no need to do any wrapping magic
return factory.getInstance(bundle,levels,defaultLevel,catalogName,message);
}
}
/**
*/
private UserPromptCondition(boolean unused,Bundle bundle,String levels,String defaultLevel,String catalogName,String message) {
this.bundle=bundle;
this.levels=levels;
this.defaultLevel=defaultLevel;
this.catalogName=catalogName;
this.message=message;
}
/**
*/
protected UserPromptCondition() {
bundle=null;
levels=null;
defaultLevel=null;
catalogName=null;
message=null;
}
public static Condition getCondition(Bundle bundle,
ConditionInfo conditionInfo) {
if (bundle == null || conditionInfo == null)
throw new NullPointerException("bundle " + bundle + " or info "
try {
// not synchronized so could theor. happen multiple times
// but that is a bit wasteful but not harmful. At least
// we keep on trying if the loading order is messed up
// and we try to use before the implementation exists.
if ( getCondition == null )
init();
return (Condition) getCondition.invoke(null, new Object[] {bundle,
conditionInfo});
}
catch (IllegalAccessException e) {
throw new RuntimeException("Implementation constructor is not public ("
}
catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof IllegalArgumentException)
throw (IllegalArgumentException) t;
/**
*/
private void lookForImplementation() {
if ((realUserPromptCondition==null)&&(factory!=null)) {
realUserPromptCondition = factory.getInstance(bundle,levels,defaultLevel,catalogName,message);
}
}
/**
*/
public boolean isPostponed() {
lookForImplementation();
if (realUserPromptCondition!=null) {
return realUserPromptCondition.isPostponed();
} else {
return true;
}
}
/**
*/
public boolean isMutable() {
lookForImplementation();
if (realUserPromptCondition!=null) {
return realUserPromptCondition.isMutable();
} else {
// since we don't know what the actual status is, we cannot say
// "the condition cannot change anymore"
return true;
}
}
/**
*/
public boolean isSatisfied() {
lookForImplementation();
if (realUserPromptCondition!=null) {
return realUserPromptCondition.isSatisfied();
} else {
// paranoid security option
return false;
}
}
/**
*/
public boolean isSatisfied(Condition[] conds, Dictionary context) {
lookForImplementation();
if (realUserPromptCondition!=null) {
return realUserPromptCondition.isSatisfied(conds,context);
} else {
// paranoid security option
return false;
throw new RuntimeException("Implementation failed: " + e); } } }
RCS file: /cvshome/build/org.osgi.impl.service.policy/src/org/osgi/impl/service/policy/userprompt/UserPromptActivator.java,v retrieving revision 1.1 diff -u -r1.1 UserPromptActivator.java --- src/org/osgi/impl/service/policy/userprompt/UserPromptActivator.java 9 May 2005 21:39:12 -0000 1.1 +++ src/org/osgi/impl/service/policy/userprompt/UserPromptActivator.java 7 Jul 2006 07:28:51 -0000 @ @ -22,12 +22,12 @ @
public class UserPromptActivator implements BundleActivator { public void start(BundleContext context) throws Exception {
UserPromptCondition.setContext(context);
UserPromptCondition.registerMySelf();
UserPromptConditionImpl.setContext(context);
UserPromptConditionImpl.registerMySelf(); }
public void stop(BundleContext context) throws Exception {
UserPromptCondition.deregisterMySelf();
UserPromptConditionImpl.deregisterMySelf(); }
RCS file: src/org/osgi/impl/service/policy/userprompt/UserPromptCondition.java diff -N src/org/osgi/impl/service/policy/userprompt/UserPromptCondition.java --- src/org/osgi/impl/service/policy/userprompt/UserPromptCondition.java 7 Mar 2006 11:05:05 -0000 1.17 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @ @ -1,430 +0,0 @ @ -/*
*/
-package org.osgi.impl.service.policy.userprompt;
-import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.io.StreamCorruptedException; -import java.util.ArrayList; -import java.util.Dictionary; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.ResourceBundle;
-import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.service.condpermadmin.Condition;
-/**
*
*/ -public class UserPromptCondition
extends org.osgi.util.mobile.UserPromptCondition
implements Serializable -{
/**
serialVersionUID
*/
private static final long serialVersionUID = 3834593218389226802L;
private static BundleContext context;
public static String ONESHOT_STRING = "ONESHOT";
public static String SESSION_STRING = "SESSION";
public static String BLANKET_STRING = "BLANKET";
public static String NEVER_STRING = "NEVER";
public static String NOSESSION_STRING = "NOSESSION";
/**
*/
static HashMap conditions;
final long bundleID;
final String catalogName;
final String message;
final String defaultLevel;
final String levels;
final boolean oneshotAllowed;
final boolean sessionAllowed;
final boolean blanketAllowed;
/**
*/
String status = null;
/**
*/
static String generateUniqueID(Bundle bundle,String catalogName,String message) {
return ""+bundle.getBundleId()+"|"+catalogName+"|"+message;
}
public boolean isPostponed() {
return status==null;
}
public boolean isMutable() {
return status==null;
// Our implementation doesn't have a separate management interface for setting permissions,
// so once the user chose for example "blanket", it will always stay that way.
}
private String getLocalizedMessage() {
String localizedMessage;
if (message.startsWith("%")) {
String messageID = message.substring(1);
ResourceBundle resourceBundle = ResourceBundle.getBundle(catalogName);
localizedMessage = resourceBundle.getString(messageID);
if (localizedMessage==null) { // fall back
localizedMessage = messageID;
}
} else {
localizedMessage = message;
}
return localizedMessage;
}
private List getPossibleAnswers() {
ArrayList al = new ArrayList(5);
if (blanketAllowed) {
al.add("always");
}
if (sessionAllowed) {
al.add("session");
al.add("nosession");
}
if (oneshotAllowed) {
al.add("yes");
al.add("no");
}
al.add("never");
return al;
}
public boolean isSatisfied() {
if (status!=null) {
if (status.equals(BLANKET_STRING)||status.equals(SESSION_STRING)) return true;
if (status.equals(NEVER_STRING)||status.equals(NOSESSION_STRING)) return false;
}
System.out.println("User Question:");
System.out.println(getLocalizedMessage());
List possibleAnswers = getPossibleAnswers();
System.out.println(possibleAnswers.toString());
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String answer = null;
while (answer==null) {
try {
answer = reader.readLine();
}
catch (IOException e) {
// TODO do log and whatever
e.printStackTrace();
return false;
}
if (possibleAnswers.contains(answer)) break;
answer = null;
}
return setAnswer(answer);
}
/**
*/
boolean setAnswer(String answer) {
// so we have an answer
boolean satisfied;
if (answer.equals("always")) {
status = BLANKET_STRING;
satisfied = true;
} else if (answer.equals("session")) {
status = SESSION_STRING;
satisfied = true;
} else if (answer.equals("never")) {
status = NEVER_STRING;
satisfied = false;
} else if (answer.equals("nosession")) {
status = NOSESSION_STRING;
satisfied = false;
} else if (answer.equals("yes")) {
satisfied = true;
} else if (answer.equals("no")) {
satisfied = false;
} else
throw new IllegalStateException("todo");
saveToStorage();
return satisfied;
}
public boolean isSatisfied(Condition[] conds, Dictionary context) {
if (context==null) context = new Hashtable();
String[] questions = new String[conds.length];
Bundle[] bundles = new Bundle[conds.length];
List[] possibleAnswers = new List[conds.length];
// first, figure out what to prompt
for(int i=0;i<conds.length;i++) {
org.osgi.util.mobile.UserPromptCondition ucond = (org.osgi.util.mobile.UserPromptCondition) conds[i];
UserPromptCondition cond = (UserPromptCondition) org.osgi.util.mobile.UserPromptCondition.unWrap(ucond);
Boolean prevAns = (Boolean) context.get(cond);
if ((prevAns!=null)||!cond.isPostponed()) {
if ((prevAns!=null)) {
if (!prevAns.booleanValue()) return false;
} else {
if (!cond.isSatisfied()) return false; // no need to do anything
}
// remove this from every array, it has been asked already
Condition[] c2 = new Condition[conds.length-1];
System.arraycopy(conds,0,c2,0,i);
System.arraycopy(conds,i+i,c2,i,conds.length-1-i);
conds = c2;
i--;
continue;
}
questions[i]=cond.getLocalizedMessage();
bundles[i]=UserPromptCondition.context.getBundle(cond.bundleID);
possibleAnswers[i] = cond.getPossibleAnswers();
}
if (conds.length==0) { return true; }
String[] answers = new String[conds.length];
// then, do the questions
System.out.println("User Question (answer with comma-separated list):");
for(int i=0;i<conds.length;i++) {
System.out.print("("+(i+1)+") ");
System.out.print(bundles[i].getSymbolicName()+": ");
System.out.print(questions[i]);
System.out.print(" ");
System.out.println(possibleAnswers[i]);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String answer = null;
while (answer==null) {
try {
answer = reader.readLine();
}
catch (IOException e) {
// TODO do log and whatever
e.printStackTrace();
return false;
}
answers = Splitter.split(answer,',',-1);
if (answers.length!=conds.length) {
System.err.println("You must answer all "+conds.length+" questions once, with a comma-separated list, no spaces");
answer = null;
continue;
}
for(int i=0;i<answers.length;i++) {
if (!possibleAnswers[i].contains(answers[i])) {
System.err.println("Answer nr. "+i+" \""+answers[i]+"\" is not valid");
answer = null;
continue;
}
}
break;
}
// then evaluate all of them, and return whether all are satisfied
boolean all_satisfied = true;
for(int i=0;i<conds.length;i++) {
org.osgi.util.mobile.UserPromptCondition ucond = (org.osgi.util.mobile.UserPromptCondition) conds[i];
UserPromptCondition cond = (UserPromptCondition) org.osgi.util.mobile.UserPromptCondition.unWrap(ucond);
boolean satisfied = cond.setAnswer(answers[i]);
context.put(cond,satisfied?Boolean.TRUE:Boolean.FALSE);
all_satisfied&=satisfied;
}
return all_satisfied;
}
static void checkConstructorParams(String levels,String defaultLevel) {
levels=levels.toUpperCase();
defaultLevel=defaultLevel.toUpperCase();
if (levels.equals("")) {
throw new IllegalArgumentException("Userprompt levels is empty string");
}
boolean oneshot = false;
boolean session = false;
boolean blanket = false;
String[] alevels = Splitter.split(levels,',',-1);
for(int i=0;i<alevels.length;i++) {
if (alevels[i].equals(ONESHOT_STRING)) { oneshot = true; }
else if (alevels[i].equals(SESSION_STRING)) { session = true; }
else if (alevels[i].equals(BLANKET_STRING)) { blanket = true; }
else throw new IllegalArgumentException("Unknown userprompt level: "+alevels[i]);
}
if (!defaultLevel.equals("") &&
!defaultLevel.equals(ONESHOT_STRING)&&
!defaultLevel.equals(SESSION_STRING)&&
!defaultLevel.equals(BLANKET_STRING))
{
throw new IllegalArgumentException("Unknown default userprompt level: "+defaultLevel);
}
if ((!oneshot && defaultLevel.equals(ONESHOT_STRING)) ||
(!session && defaultLevel.equals(SESSION_STRING)) ||
(!blanket && defaultLevel.equals(BLANKET_STRING)))
{
throw new IllegalArgumentException("Default userprompt level is not among possible levels: "+defaultLevel);
}
}
protected UserPromptCondition(Bundle bundle, String levels, String defaultLevel, String catalogName, String message) {
levels=levels.toUpperCase();
defaultLevel=defaultLevel.toUpperCase();
this.bundleID = bundle.getBundleId();
this.catalogName = catalogName;
this.message = message;
this.defaultLevel = defaultLevel;
this.levels = levels;
if (levels.equals("")) {
throw new IllegalArgumentException("Userprompt levels is empty string");
}
boolean oneshot = false;
boolean session = false;
boolean blanket = false;
String[] alevels = Splitter.split(levels,',',-1);
for(int i=0;i<alevels.length;i++) {
if (alevels[i].equals(ONESHOT_STRING)) { oneshot = true; }
else if (alevels[i].equals(SESSION_STRING)) { session = true; }
else if (alevels[i].equals(BLANKET_STRING)) { blanket = true; }
else throw new IllegalArgumentException("Unknown userprompt level: "+alevels[i]);
}
oneshotAllowed = oneshot;
sessionAllowed = session;
blanketAllowed = blanket;
if (!defaultLevel.equals("") &&
!defaultLevel.equals(ONESHOT_STRING)&&
!defaultLevel.equals(SESSION_STRING)&&
!defaultLevel.equals(BLANKET_STRING))
{
throw new IllegalArgumentException("Unknown default userprompt level: "+defaultLevel);
}
if ((!oneshotAllowed && defaultLevel.equals(ONESHOT_STRING)) ||
(!sessionAllowed && defaultLevel.equals(SESSION_STRING)) ||
(!blanketAllowed && defaultLevel.equals(BLANKET_STRING)))
{
throw new IllegalArgumentException("Default userprompt level is not among possible levels: "+defaultLevel);
}
}
public static class Factory implements org.osgi.util.mobile.UserPromptCondition.UserPromptConditionFactory {
public org.osgi.util.mobile.UserPromptCondition getInstance(Bundle bundle, String levels, String defaultLevel, String catalogName, String message) {
checkConstructorParams(levels,defaultLevel);
String id = generateUniqueID(bundle,catalogName,message);
UserPromptCondition condition = (UserPromptCondition) conditions.get(id);
if (condition==null) {
condition = new UserPromptCondition(bundle,levels,defaultLevel,catalogName,message);
conditions.put(id,condition);
}
return condition;
}
}
public static void setContext(BundleContext context) {
UserPromptCondition.context = context;
}
public static void saveToStorage() {
// TODO: this is a rather unsophisticated method....
File stateFile = context.getDataFile("state");
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(stateFile));
oos.writeObject(conditions);
oos.close();
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
public static void deregisterMySelf() {
conditions = null;
org.osgi.util.mobile.UserPromptCondition.setFactory(null);
}
public static void registerMySelf() throws StreamCorruptedException, IOException, ClassNotFoundException {
File stateFile = context.getDataFile("state");
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(stateFile));
conditions = (HashMap) ois.readObject();
} catch (FileNotFoundException e) {
conditions = new HashMap();
}
// this counts as a new session, so we have to delete every "session" permission
for(Iterator i = conditions.values().iterator();i.hasNext();) {
UserPromptCondition cond = (UserPromptCondition) i.next();
if (SESSION_STRING.equals(cond.status)) cond.status = null;
if (NOSESSION_STRING.equals(cond.status)) cond.status = null;
}
org.osgi.util.mobile.UserPromptCondition.setFactory(new Factory());
}
public boolean equals(Object var0) {
return this==var0;
}
RCS file: /cvshome/build/org.osgi.impl.service.policy/.classpath,v retrieving revision 1.12 diff -u -r1.12 .classpath --- .classpath 11 May 2006 03:12:52 -0000 1.12 +++ .classpath 7 Jul 2006 07:28:51 -0000 @ @ -1,8 +1,9 @ @ <?xml version="1.0" encoding="UTF-8"?>
RCS file: src/org/osgi/impl/service/policy/userprompt/UserPromptConditionImpl.java diff -N src/org/osgi/impl/service/policy/userprompt/UserPromptConditionImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/osgi/impl/service/policy/userprompt/UserPromptConditionImpl.java 1 Jan 1970 00:00:00 -0000 @ @ -0,0 +1,408 @ @ +/*
*/
+package org.osgi.impl.service.policy.userprompt;
+import java.io.; +import java.util.;
+import org.osgi.framework.; +import org.osgi.service.condpermadmin.;
+/**
*/ +public class UserPromptConditionImpl implements Serializable, Condition {
/**
serialVersionUID
*/
private static final long serialVersionUID = 3834593218389226802L;
private static BundleContext context;
public static String ONESHOT_STRING = "ONESHOT";
public static String SESSION_STRING = "SESSION";
public static String BLANKET_STRING = "BLANKET";
public static String NEVER_STRING = "NEVER";
public static String NOSESSION_STRING = "NOSESSION";
/**
*/
static HashMap conditions;
final long bundleID;
final String catalogName;
final String message;
final String defaultLevel;
final String levels;
final boolean oneshotAllowed;
final boolean sessionAllowed;
final boolean blanketAllowed;
/**
*/
String status = null;
/**
*/
static String generateUniqueID(Bundle bundle, String catalogName,
String message) {
return "" + bundle.getBundleId() + "|" + catalogName + "|" + message;
}
public boolean isPostponed() {
return status == null;
}
public boolean isMutable() {
return status == null;
// Our implementation doesn't have a separate management interface for
// setting permissions,
// so once the user chose for example "blanket", it will always stay
// that way.
}
private String getLocalizedMessage() {
String localizedMessage;
if (message.startsWith("%")) {
String messageID = message.substring(1);
ResourceBundle resourceBundle = ResourceBundle
.getBundle(catalogName);
localizedMessage = resourceBundle.getString(messageID);
if (localizedMessage == null) { // fall back
localizedMessage = messageID;
}
}
else {
localizedMessage = message;
}
return localizedMessage;
}
private List getPossibleAnswers() {
ArrayList al = new ArrayList(5);
if (blanketAllowed) {
al.add("always");
}
if (sessionAllowed) {
al.add("session");
al.add("nosession");
}
if (oneshotAllowed) {
al.add("yes");
al.add("no");
}
al.add("never");
return al;
}
public boolean isSatisfied() {
if (status != null) {
if (status.equals(BLANKET_STRING) || status.equals(SESSION_STRING))
return true;
if (status.equals(NEVER_STRING) || status.equals(NOSESSION_STRING))
return false;
}
System.out.println("User Question:");
System.out.println(getLocalizedMessage());
List possibleAnswers = getPossibleAnswers();
System.out.println(possibleAnswers.toString());
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String answer = null;
while (answer == null) {
try {
answer = reader.readLine();
}
catch (IOException e) {
// TODO do log and whatever
e.printStackTrace();
return false;
}
if (possibleAnswers.contains(answer))
break;
answer = null;
}
return setAnswer(answer);
}
/**
*/
boolean setAnswer(String answer) {
// so we have an answer
boolean satisfied;
if (answer.equals("always")) {
status = BLANKET_STRING;
satisfied = true;
}
else if (answer.equals("session")) {
status = SESSION_STRING;
satisfied = true;
}
else if (answer.equals("never")) {
status = NEVER_STRING;
satisfied = false;
}
else if (answer.equals("nosession")) {
status = NOSESSION_STRING;
satisfied = false;
}
else if (answer.equals("yes")) {
satisfied = true;
}
else if (answer.equals("no")) {
satisfied = false;
}
else
throw new IllegalStateException("todo");
saveToStorage();
return satisfied;
}
public boolean isSatisfied(Condition[] conds, Dictionary context) {
if (context == null)
context = new Hashtable();
String[] questions = new String[conds.length];
Bundle[] bundles = new Bundle[conds.length];
List[] possibleAnswers = new List[conds.length];
// first, figure out what to prompt
for (int i = 0; i < conds.length; i++) {
UserPromptConditionImpl cond = (UserPromptConditionImpl) conds[i];
Boolean prevAns = (Boolean) context.get(cond);
if ((prevAns != null) || !cond.isPostponed()) {
if ((prevAns != null)) {
if (!prevAns.booleanValue())
return false;
}
else {
if (!cond.isSatisfied())
return false; // no need to do anything
}
// remove this from every array, it has been asked already
Condition[] c2 = new Condition[conds.length - 1];
System.arraycopy(conds, 0, c2, 0, i);
System.arraycopy(conds, i + i, c2, i, conds.length - 1 - i);
conds = c2;
i--;
continue;
}
questions[i] = cond.getLocalizedMessage();
bundles[i] = UserPromptConditionImpl.context.getBundle(cond.bundleID);
possibleAnswers[i] = cond.getPossibleAnswers();
}
if (conds.length == 0) {
return true;
}
String[] answers = new String[conds.length];
// then, do the questions
System.out.println("User Question (answer with comma-separated list):");
for (int i = 0; i < conds.length; i++) {
System.out.print("(" + (i + 1) + ") ");
System.out.print(bundles[i].getSymbolicName() + ": ");
System.out.print(questions[i]);
System.out.print(" ");
System.out.println(possibleAnswers[i]);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
String answer = null;
while (answer == null) {
try {
answer = reader.readLine();
}
catch (IOException e) {
// TODO do log and whatever
e.printStackTrace();
return false;
}
answers = Splitter.split(answer, ',', -1);
if (answers.length != conds.length) {
System.err
.println("You must answer all "
answer = null;
continue;
}
for (int i = 0; i < answers.length; i++) {
if (!possibleAnswers[i].contains(answers[i])) {
System.err.println("Answer nr. " + i + " \"" + answers[i]
answer = null;
continue;
}
}
break;
}
// then evaluate all of them, and return whether all are satisfied
boolean all_satisfied = true;
for (int i = 0; i < conds.length; i++) {
UserPromptConditionImpl cond = (UserPromptConditionImpl) conds[i];
boolean satisfied = cond.setAnswer(answers[i]);
context.put(cond, satisfied ? Boolean.TRUE : Boolean.FALSE);
all_satisfied &= satisfied;
}
return all_satisfied;
}
UserPromptConditionImpl(Bundle bundle, ConditionInfo info) {
String[] args = info.getArgs();
if (args.length != 4)
throw new IllegalArgumentException("args.length==" + args.length
if ( args[0]==null || args[1]==null || args[2]==null || args[3]==null)
throw new IllegalArgumentException("One of the arguments is null");
levels = args[0].toUpperCase();
defaultLevel = args[1].toUpperCase();
catalogName = args[2];
message = args[3];
this.bundleID = bundle.getBundleId();
if (levels.equals("")) {
throw new IllegalArgumentException(
"Userprompt levels is empty string");
}
boolean oneshot = false;
boolean session = false;
boolean blanket = false;
String[] alevels = Splitter.split(levels, ',', -1);
for (int i = 0; i < alevels.length; i++) {
if (alevels[i].equals(ONESHOT_STRING)) {
oneshot = true;
}
else if (alevels[i].equals(SESSION_STRING)) {
session = true;
}
else if (alevels[i].equals(BLANKET_STRING)) {
blanket = true;
}
else
throw new IllegalArgumentException("Unknown userprompt level: "
}
oneshotAllowed = oneshot;
sessionAllowed = session;
blanketAllowed = blanket;
if (!defaultLevel.equals("") && !defaultLevel.equals(ONESHOT_STRING)
&& !defaultLevel.equals(SESSION_STRING)
&& !defaultLevel.equals(BLANKET_STRING)) {
throw new IllegalArgumentException(
"Unknown default userprompt level: " + defaultLevel);
}
if ((!oneshotAllowed && defaultLevel.equals(ONESHOT_STRING))
|| (!sessionAllowed && defaultLevel.equals(SESSION_STRING))
|| (!blanketAllowed && defaultLevel.equals(BLANKET_STRING))) {
throw new IllegalArgumentException(
"Default userprompt level is not among possible levels: "
}
}
public static void setContext(BundleContext context) {
UserPromptConditionImpl.context = context;
}
public static void saveToStorage() {
// TODO: this is a rather unsophisticated method....
File stateFile = context.getDataFile("state");
try {
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(stateFile));
oos.writeObject(conditions);
oos.close();
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
}
public static void deregisterMySelf() {
conditions = null;
}
public static void registerMySelf() throws StreamCorruptedException,
IOException, ClassNotFoundException {
File stateFile = context.getDataFile("state");
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
stateFile));
conditions = (HashMap) ois.readObject();
ois.close();
}
catch (FileNotFoundException e) {
conditions = new HashMap();
}
// this counts as a new session, so we have to delete every "session"
// permission
for (Iterator i = conditions.values().iterator(); i.hasNext();) {
UserPromptConditionImpl cond = (UserPromptConditionImpl) i.next();
if (SESSION_STRING.equals(cond.status))
cond.status = null;
if (NOSESSION_STRING.equals(cond.status))
cond.status = null;
}
}
public static Condition getCondition(Bundle bundle, ConditionInfo info ) {
return new UserPromptConditionImpl(bundle,info);
} +}
Comment author: Peter Nagy <peter.1.nagy@nokia.com>
I've committed new org.osgi.util.mobile.UserPromptCondition version, all unofficial methods are either private or package-protected now.
Comment author: @bjhargrave
Change to UserPromptCondition has causes the test to fail in the daily build:
From http://membercvs.osgi.org/db/osgi.test/director/run-mobile.xml#test.policy
085848.133 test.policy_TBC #testGetCondition012 085848.219 test.policy_TBC X testUserPromptConditionGetCondition: "# expected:[java.lang.IllegalArgumentException] and got nothing" [result] [reference]
Comment author: Peter Nagy <peter.1.nagy@nokia.com>
right, I forgot to unwrap some exceptions. It is fixed now
Original bug ID: BZ#332 From: @bjhargrave Reported version: R4