| /* |
| * $Header: /cvshome/build/org.osgi.util.mobile/src/org/osgi/util/mobile/UserPromptCondition.java,v 1.26 2006/07/10 08:18:30 pnagy Exp $ |
| * |
| * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.osgi.util.mobile; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.Dictionary; |
| |
| import org.osgi.framework.Bundle; |
| import org.osgi.service.condpermadmin.Condition; |
| import org.osgi.service.condpermadmin.ConditionInfo; |
| |
| /** |
| * Class representing a user prompt condition. Instances of this class hold two |
| * values: a prompt string that is to be displayed to the user and the |
| * permission level string according to MIDP2.0 (oneshot, session, blanket). |
| * |
| */ |
| public class UserPromptCondition implements Condition { |
| |
| /* |
| * NOTE: An implementor may also choose to replace this class in |
| * their distribution with a class that directly interfaces with the |
| * policy implementation. This replacement class MUST NOT alter the |
| * public/protected signature of this class. |
| */ |
| // this will need to be set by the implementation class |
| static Method factory = null; |
| Condition realUserPromptCondition; |
| |
| private final Bundle bundle; |
| private final String levels; |
| private final String defaultLevel; |
| private final String catalogName; |
| private final String message; |
| |
| /** |
| * Returns a UserPromptCondition object with the given prompt string and permission |
| * level. The user should be given choice as to what level of permission is |
| * given. Thus, the lifetime of the permission is controlled by the user. |
| * |
| * @param bundle the bundle to ask about. |
| * @param conditionInfo the conditionInfo containing the construction information. Its |
| * {@link ConditionInfo#getArgs()} method should return a String array with 4 |
| * strings in it: |
| * <ol start="0"> |
| * <li>the possible permission levels. This is a comma-separated list that can contain |
| * following strings: ONESHOT SESSION BLANKET. The order is not important. This |
| * parameter is case-insensitive. |
| * </li> |
| * <li>the default permission level, one chosen from the possible permission levels. If |
| * it is an empty string, then there is no default. This parameter |
| * is case-insensitive.</li> |
| * <li>the message catalog base name. It will be loaded by a {@link java.util.ResourceBundle}, |
| * or equivalent |
| * from an exporting OSGi Bundle. Thus, if the catalogName is "com.provider.messages.userprompt", |
| * then there should be an OSGi Bundle exporting the "com.provider.messages" package, and inside |
| * it files like "userprompt_en_US.properties".</li> |
| * <li>textual description of the condition, to be displayed to the user. If |
| * it starts with a '%' sign, then the message is looked up from the catalog specified previously. |
| * The key is the rest of the string after the '%' sign.</li> |
| * </ol> |
| * @return The requested UserPromptCondition. |
| * @throws IllegalArgumentException if the parameters are malformed. |
| * @throws NullPointerException if one of the parameters is <code>null</code>. |
| */ |
| 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(bundle,levels,defaultLevel,catalogName,message); |
| } else { |
| // there is already a factory, no need to do any wrapping magic |
| try { |
| return (Condition) factory.invoke(null,new Object[]{bundle,levels,defaultLevel,catalogName,message}); |
| } catch (IllegalAccessException e) { |
| e.printStackTrace(); |
| } catch (InvocationTargetException e) { |
| Throwable original = e.getTargetException(); |
| if (original instanceof NullPointerException) throw (NullPointerException) original; |
| if (original instanceof IllegalArgumentException) throw (IllegalArgumentException) original; |
| e.printStackTrace(); |
| } |
| // the factory method is not working, fallback behavior: |
| factory = null; |
| return new UserPromptCondition(bundle,levels,defaultLevel,catalogName,message); |
| } |
| } |
| |
| /** |
| * Instances of the UserPromptCondition are simply store the construction parameters |
| * until a "real" UserPromptCondition is registered in setFactory(). At that point, it |
| * will delegate all calls there. |
| * @param unused this parameter is here so that ConditionalPermissionAdmin would not |
| * use this as the constructor instead of the getInstance |
| * @param bundle |
| * @param levels |
| * @param defaultLevel |
| * @param catalogName |
| * @param message |
| */ |
| private UserPromptCondition(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; |
| } |
| |
| /** |
| * Check if a factory is registered, and if yes, create userprompt to delegate calls to. |
| */ |
| private void lookForImplementation() { |
| if ((realUserPromptCondition==null)&&(factory!=null)) { |
| try { |
| realUserPromptCondition = (Condition) factory.invoke(null,new Object[]{bundle,levels,defaultLevel,catalogName,message}); |
| return; |
| } catch (IllegalAccessException e) { |
| e.printStackTrace(); |
| } catch (InvocationTargetException e) { |
| e.printStackTrace(); |
| } |
| // only if the factory call fails with some invocation exception |
| factory = null; |
| } |
| } |
| |
| /** |
| * Checks if the {@link #isSatisfied()} method needs to prompt the user, thus cannot |
| * give results instantly. |
| * This depends on the permission level given in |
| * {@link UserPromptCondition#getCondition(Bundle, ConditionInfo)}. |
| * <ul> |
| * <li>ONESHOT - isPostponed always returns true. The user is prompted for question every time.</li> |
| * <li>SESSION - isPostponed returns true until the user decides either yes or no for the current session.</li> |
| * <li>BLANKET - isPostponed returns true until the user decides either always or never.</li> |
| * </ul> |
| * Regardless of the session level, the user is always given the option to reject the prompt |
| * permanently, as if BLANKET/never was chosen. In this case, the question is not postponed |
| * anymore, and {@link #isSatisfied()} returns false.<br/> |
| * If the system supports an separately accessible permission management GUI, |
| * that may reset the condition |
| * to its initial state. |
| * |
| * @return True, if user interaction is needed. |
| */ |
| public boolean isPostponed() { |
| lookForImplementation(); |
| if (realUserPromptCondition!=null) { |
| return realUserPromptCondition.isPostponed(); |
| } else { |
| return true; |
| } |
| } |
| |
| /** |
| * Checks whether the condition may change during the lifetime of the UserPromptCondition object. |
| * This depends on the permission level given in |
| * {@link UserPromptCondition#getCondition(Bundle, ConditionInfo)}. |
| * <ul> |
| * <li>ONESHOT - true</li> |
| * <li>SESSION - true, if the application model's session lifetime is |
| * shorter than the UserPromptCondition object lifetime</li> |
| * <li>BLANKET - false</li> |
| * </ul> |
| * If the system supports separately accessible permission management GUI, |
| * then this function may also return true for SESSION and BLANKET. |
| * |
| * @return True, if the condition can change. |
| */ |
| 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; |
| } |
| } |
| |
| /** |
| * Displays the prompt string to |
| * the user and returns true if the user accepts. Depending on the |
| * amount of levels the condition is assigned to, the prompt may have |
| * multiple accept buttons and one of them can be selected by default (see |
| * default level parameter at {@link UserPromptCondition#getCondition(Bundle, ConditionInfo)}). |
| * It must always be possible for the user |
| * to stop further prompting of this question, even with ONESHOT and SESSION levels. |
| * In case of BLANKET |
| * and SESSION levels, it is possible that the user has already answered the question, |
| * in this case there will be no prompting, but immediate return with the previous answer. |
| * |
| * @return True if the user accepts the prompt (or accepts any prompt in |
| * case there are multiple permission levels). |
| */ |
| public boolean isSatisfied() { |
| lookForImplementation(); |
| if (realUserPromptCondition!=null) { |
| return realUserPromptCondition.isSatisfied(); |
| } else { |
| // paranoid security option |
| return false; |
| } |
| } |
| |
| /** |
| * Checks an array of UserPrompt conditions. |
| * |
| * @param conds The array containing the UserPrompt conditions to evaluate. |
| * @param context Storage area for evaluation. The {@link org.osgi.service.condpermadmin.ConditionalPermissionAdmin} |
| * may evaluate a condition several times for one permission check, so this context |
| * will be used to store results of ONESHOT questions. This way asking the same question |
| * twice in a row can be avoided. If context is null, temporary results will not be stored. |
| * @return True, if all conditions are satisfied. |
| * @throws NullPointerException if conds is null. |
| */ |
| public boolean isSatisfied(Condition[] conds, Dictionary context) { |
| lookForImplementation(); |
| if (realUserPromptCondition!=null) { |
| return realUserPromptCondition.isSatisfied(conds,context); |
| } else { |
| // paranoid security option |
| return false; |
| } |
| } |
| } |