public String toXml()
	{
		final String lqSimpleName = this.getClass().getSimpleName().toLowerCase();
		final Map<String, Class<?>> aliases = new HashMap<>();
		aliases.put(lqSimpleName, this.getClass());
		return ObjectToXmlExtensions.toXmlWithXStream(this, aliases);
	}

public String toXml ( ) { final String lqSimpleName = this . getClass ( ) . getSimpleName ( ) . toLowerCase ( ) ; final Map < String , Class < ? > > aliases = new HashMap <> ( ) ; aliases . put ( lqSimpleName , this . getClass ( ) ) ; return ObjectToXmlExtensions . toXmlWithXStream ( this , aliases ) ; }


private void setContentViewWithMinimalElements() {
        // Set data in the RemoteViews programmatically
        contentView.setImageViewResource(R.id.imageView, R.drawable.ic_launcher);
        contentView.setTextViewText(R.id.title_text_notification, getResources().getString(R.string.notification_title));
        contentView.setTextViewText(R.id.message_notification, getResources().getString(R.string.notification_text));
    }

Method to set the contentview with Title, Text and Image.

Method to set the contentview with Title Text and Image .


public String getFriendlyNameOfField(ProfileField<?> field) {
		String name = getStringFromResource(PROFILE_FIELD_PREFIX + field.getIdentifier());
		if(name == null){
			return field.getIdentifier();
		}

		return name;
	}

public String getFriendlyNameOfField ( ProfileField < ? > field ) { String name = getStringFromResource ( PROFILE_FIELD_PREFIX + field . getIdentifier ( ) ) ; if ( name == null ) { return field . getIdentifier ( ) ; } return name ; }

Provides the localized friendly name of a field.
@param field - the field whose name to retrieve
@return the friendly name of the field

Provides the localized friendly name of a field .


private void killScheduler() {
        if (scheduler != null) {
            WfdLog.d(TAG, "scheduler killed");
            scheduler.shutdown();
            scheduler = null;
        }
    }

private
void
killScheduler
(
)
{
if
(
scheduler
!=
)
{
WfdLog
.
d
(
TAG
,
"scheduler killed"
)
;
scheduler
.
shutdown
(
)
;
scheduler
=
;
}
}

Kill the scheduler to stop the Eternal Connect in any case.

Kill the scheduler to stop the Eternal Connect in any case .


public static synchronized void initialize(Context context, int goIntent, boolean isAutonomous,
                                               ProximityMiddleware.Factory factory) {
        if (context == null || factory == null) {
            throw new NullPointerException("Arguments cannot be null");
        }

        SPF.initialize(context, goIntent, isAutonomous, factory);
        sInstance = new SPFContext();
    }

public
static
synchronized
void
initialize
(
Context
context
,
int
goIntent
,
boolean
isAutonomous
,
ProximityMiddleware
.
Factory
factory
)
{
if
(
context
==
||
factory
==
)
{
throw
new
NullPointerException
(
"Arguments cannot be null"
)
;
}
SPF
.
initialize
(
context
,
goIntent
,
isAutonomous
,
factory
)
;
sInstance
=
new
SPFContext
(
)
;
}

Initializes SPFContext. After this method has been called, you can get
references to SPFContext and SPF.

@param context

Initializes SPFContext . After this method has been called you can get references to SPFContext and SPF .


public void broadcastEvent(final int code, final Bundle payload) {
        if (SPFConfig.DEBUG) {
            Log.d(TAG, "Broadcasting event " + code + " with payload " + payload);
        }

        for (final OnEventListener listener : mEventListeners) {//TODO is it thread safe?
            mHandler.post(new Runnable() {

                @Override
                public void run() {
                    listener.onEvent(code, payload);
                }
            });
        }
    }

public
void
broadcastEvent
(
final
int
code
,
final
Bundle
payload
)
{
if
(
SPFConfig
.
DEBUG
)
{
Log
.
d
(
TAG
,
"Broadcasting event "
+
code
+
" with payload "
+
payload
)
;
}
for
(
final
OnEventListener
listener
:
mEventListeners
)
{
//TODO is it thread safe?
mHandler
.
post
(
new
Runnable
(
)
{
@
Override
public
void
run
(
)
{
listener
.
onEvent
(
code
,
payload
)
;
}
}
)
;
}
}

Broadcasts an event to all registered listeners. Each listener will
receive a reference to the given bundle.

@param code    - the event code
@param payload - the event payload

Broadcasts an event to all registered listeners . Each listener will receive a reference to the given bundle .


public static ProfileFragment createViewSelfProfileFragment() {
        Bundle b = new Bundle();
        b.putInt(EXTRA_VIEW_MODE, Mode.SELF.ordinal());
        ProfileFragment fragment = new ProfileFragment();
        fragment.setArguments(b);
        return fragment;
    }

public static ProfileFragment createViewSelfProfileFragment ( ) { Bundle b = new Bundle ( ) ; b . putInt ( EXTRA_VIEW_MODE , Mode . SELF . ordinal ( ) ) ; ProfileFragment fragment = new ProfileFragment ( ) ; fragment . setArguments ( b ) ; return fragment ; }

Creates a new instance of ProfileFragment to show the local profile.

@return an instance of ProfileFragment

Creates a new instance of ProfileFragment to show the local profile .


private void onProfileDataAvailable() {
        Log.d(TAG, "onProfileDataAvailable");
        mFactory = new ProfileFieldViewFactory(getActivity(), mMode, mCurrentPersona, mContainer);

        String[] mPageTitles = this.getResources().getStringArray(R.array.profileedit_fragments_titles);

        tabLayout.removeAllTabs();
        tabLayout.addTab(tabLayout.newTab().setText(mPageTitles[0].toUpperCase(Locale.getDefault())));
        tabLayout.addTab(tabLayout.newTab().setText(mPageTitles[1].toUpperCase(Locale.getDefault())));
        tabLayout.addTab(tabLayout.newTab().setText(mPageTitles[2].toUpperCase(Locale.getDefault())));
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

        ProfilePagerAdapter mPagerAdapter = new ProfilePagerAdapter(getChildFragmentManager(), mMode, tabLayout.getTabCount());

        mViewPager.setAdapter(mPagerAdapter);
        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                mViewPager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });

        if (mMode != Mode.SELF) {
            showPicture(mContainer.getFieldValue(ProfileField.PHOTO));
        } else {
            if (getActivity() instanceof MainActivity) {
                ((MainActivity) getActivity()).onPhotoReady(mContainer.getFieldValue(ProfileField.PHOTO));
            } else if (getActivity() instanceof ProfileViewActivity) {
                //TODO implement this
//                ((ProfileViewActivity) getActivity()).onPhotoReady(mContainer.getFieldValue(ProfileField.PHOTO));
            }
        }

        // Refresh field fragments
        mPagerAdapter.onRefresh();
    }

Called when the profile data is available, thus we can set up the view

Called when the profile data is available thus we can set up the view


public void beginCrop(Uri source) {
        Uri destination = Uri.fromFile(new File(this.getActivity().getCacheDir(), "cropped"));
        Crop.of(source, destination).asSquare().start(this.getActivity());
    }

public void beginCrop ( Uri source ) { Uri destination = Uri . fromFile ( new File ( this . getActivity ( ) . getCacheDir ( ) , "cropped" ) ) ; Crop . of ( source , destination ) . asSquare ( ) . start ( this . getActivity ( ) ) ; }

Method to start the activity to crop an image.

@param source

Method to start the activity to crop an image .


public void handleCrop(int resultCode, Intent result) {
        if (resultCode == Activity.RESULT_OK) {
            Uri uri = Crop.getOutput(result);
            resultView.setImageURI(uri);

            InputStream inputStream = null;
            try {
                inputStream = new FileInputStream(uri.getPath());
                Bitmap myBitmap = BitmapFactory.decodeStream(inputStream);
                myBitmap = Bitmap.createScaledBitmap(myBitmap, 130, 130, false);

                mContainer.setFieldValue(ProfileField.PHOTO, myBitmap);
                showPicture(myBitmap);

            } catch (FileNotFoundException e) {
                Log.e(TAG, "handleCrop FileInputStream-file not found from uri.getpath", e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        Log.e(TAG, "handleCrop closing input stream error", e);
                    }
                }
            }
        } else if (resultCode == Crop.RESULT_ERROR) {
            Toast.makeText(this.getActivity(), Crop.getError(result).getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

Method to set an show a cropped imaged.

@param resultCode
@param result

Method to set an show a cropped imaged .


public static <T> String toJson(final T object, final boolean newMapper)
		throws JsonProcessingException
	{
		final ObjectMapper mapper = ObjectMapperFactory.getObjectMapper(newMapper);
		final String json = mapper.writeValueAsString(object);
		return json;
	}

public static < T > String toJson ( final T object , final boolean newMapper ) throws JsonProcessingException { final ObjectMapper mapper = ObjectMapperFactory . getObjectMapper ( newMapper ) ; final String json = mapper . writeValueAsString ( object ) ; return json ; }

To json.

@param <T>
the generic type
@param object
the object
@param newMapper
flag that indicates if a new ObjectMapper should be created. if true a new
ObjectMapper will be created otherwise the ObjectMapper from this class will be
returned.
@return the string
@throws JsonProcessingException
If an error occurs when converting object to String


public void addTag(String tag) {
		TagBubble tb = new TagBubble(getContext());
		tb.setText(tag);
		tb.setEditable(editable);
		tb.setOnRemoveTagListener(bubbleClickListener);
		tags.add(tag.toString());
		addView(tb);
	}

public void addTag ( String tag ) { TagBubble tb = new TagBubble ( getContext ( ) ) ; tb . setText ( tag ) ; tb . setEditable ( editable ) ; tb . setOnRemoveTagListener ( bubbleClickListener ) ; tags . add ( tag . toString ( ) ) ; addView ( tb ) ; }


public void setTags(List<String> tags) {
		this.tags.clear();
		removeAllViews();
		for (String tag : tags) {
			addTag(tag);
		}
	}

public void setTags ( List < String > tags ) { this . tags . clear ( ) ; removeAllViews ( ) ; for ( String tag : tags ) { addTag ( tag ) ; } }

Set the list of tags to be displayed.

@param tags


public long saveTrigger(SPFTrigger trigger, String appPackageName) {
        trigger = mTriggerTable.saveTrigger(trigger, appPackageName);
        if (trigger != null) {
            if (mHandler != null)
                mHandler.postAddTrigger(trigger);
            return trigger.getId();
        } else {
            return -1;
        }
    }

public long saveTrigger ( SPFTrigger trigger , String appPackageName ) { trigger = mTriggerTable . saveTrigger ( trigger , appPackageName ) ; if ( trigger != null ) { if ( mHandler != null ) mHandler . postAddTrigger ( trigger ) ; return trigger . getId ( ) ; } else { return - 1 ; } }

Saves the trigger on the database.

@param t


public boolean deleteTrigger(long id, String appPackageName) {

        boolean success = mTriggerTable.deleteTrigger(id, appPackageName);
        if (success) {
            if (mHandler != null)
                mHandler.postRemoveTrigger(id);
        }
        return success;
    }

public boolean deleteTrigger ( long id , String appPackageName ) { boolean success = mTriggerTable . deleteTrigger ( id , appPackageName ) ; if ( success ) { if ( mHandler != null ) mHandler . postRemoveTrigger ( id ) ; } return success ; }

Deletes the trigger specified by its id.

@param id
@return true if the trigger has been deleted

Deletes the trigger specified by its id .


public void start() {
        this.mHandlerThread = new HandlerThread("notification-handler-thread");
        this.mHandlerThread.start();
        this.mHandler = new SPFNotificationHandler(mHandlerThread.getLooper());
        mHandler.postSetup(this);
        isRunning = true;
    }

public void start ( ) { this . mHandlerThread = new HandlerThread ( "notification-handler-thread" ) ; this . mHandlerThread . start ( ) ; this . mHandler = new SPFNotificationHandler ( mHandlerThread . getLooper ( ) ) ; mHandler . postSetup ( this ) ; isRunning = true ; }

Initialize and start all the threads and resources used by
SPFNotification service. Call this method to initialize the logic that
handles triggers processing.

Initialize and start all the threads and resources used by SPFNotification service . Call this method to initialize the logic that handles triggers processing .


private void startRegistration() {
        //  Create a string map containing information about your service.
        Map<String, String> mRecordMap = new HashMap<>();
        mRecordMap.put(Configuration.PORT, Integer.toString(mPort));
        mRecordMap.put(Configuration.IDENTIFIER, myIdentifier);

        // Service information.  Pass it an instance name, service type
        // Configuration.SERVICE_REG_TYPE , and the map containing
        // information other devices will want once they connect to this one.
        WifiP2pDnsSdServiceInfo mInfo = WifiP2pDnsSdServiceInfo.newInstance(
                Configuration.SERVICE_INSTANCE + myIdentifier,
                Configuration.SERVICE_REG_TYPE, mRecordMap);

        // Add the local service, sending the service info, network channel,
        // and listener that will be used to indicate success or failure of
        // the request.
        mManager.addLocalService(mChannel, mInfo,
                new CustomizableActionListener(
                        this.mContext,
                        TAG,
                        "Added Local Service",
                        null,
                        "Failed to add a service",
                        "Failed to add a service",
                        true)); //important: sets true to get detailed message when this method fails

    }


public String addAttribute(final String name, final String value)
	{
		if (getAttributes() == null)
		{
			this.attributes = MapFactory.newLinkedHashMap();
		}
		return getAttributes().put(name, value);
	}

public String addAttribute ( final String name , final String value ) { if ( getAttributes ( ) == null ) { this . attributes = MapFactory . newLinkedHashMap ( ) ; } return getAttributes ( ) . put ( name , value ) ; }

Adds the attribute with the given name and value.

@param name
the name
@param value
the value
@return the string

Adds the attribute with the given name and value .


public InvocationResponse invokeMethod(InvocationRequest request) {
		String methodName = request.getMethodName();

		if (!mMethodIndex.containsKey(methodName)) {
			String msg = String.format(ErrorMsg.METHOD_NOT_FOUND, methodName, mServiceDescriptor.getServiceName());
			return InvocationResponse.error(msg);
		}

		Method m = mMethodIndex.get(methodName);
		Object[] params;
		try {
			params = deserializeParameters(request.getPayload(), m.getGenericParameterTypes());
		} catch (ServiceInvocationException e) {
			return InvocationResponse.error("Error deserializing parameters:" + e.getMessage());
		}

		try {
			Object result = m.invoke(mImplementation, params);
			String json = GsonHelper.gson.toJson(result);
			return InvocationResponse.result(json);
		} catch (IllegalAccessException e) {
			return InvocationResponse.error(e);
		} catch (IllegalArgumentException e) {
			return InvocationResponse.error(ErrorMsg.ILLEGAL_ARGUMENT);
		} catch (InvocationTargetException e) {
			return InvocationResponse.error(e.getCause());
		}
	}

public
InvocationResponse
invokeMethod
(
InvocationRequest
request
)
{
String
methodName
=
request
.
getMethodName
(
)
;
if
(
!
mMethodIndex
.
containsKey
(
methodName
)
)
{
String
msg
=
String
.
format
(
ErrorMsg
.
METHOD_NOT_FOUND
,
methodName
,
mServiceDescriptor
.
getServiceName
(
)
)
;
return
InvocationResponse
.
error
(
msg
)
;
}
Method
m
=
mMethodIndex
.
get
(
methodName
)
;
Object
[
]
params
;
try
{
params
=
deserializeParameters
(
request
.
getPayload
(
)
,
m
.
getGenericParameterTypes
(
)
)
;
}
catch
(
ServiceInvocationException
e
)
{
return
InvocationResponse
.
error
(
"Error deserializing parameters:"
+
e
.
getMessage
(
)
)
;
}
try
{
Object
result
=
m
.
invoke
(
mImplementation
,
params
)
;
String
json
=
GsonHelper
.
gson
.
toJson
(
result
)
;
return
InvocationResponse
.
result
(
json
)
;
}
catch
(
IllegalAccessException
e
)
{
return
InvocationResponse
.
error
(
e
)
;
}
catch
(
IllegalArgumentException
e
)
{
return
InvocationResponse
.
error
(
ErrorMsg
.
ILLEGAL_ARGUMENT
)
;
}
catch
(
InvocationTargetException
e
)
{
return
InvocationResponse
.
error
(
e
.
getCause
(
)
)
;
}
}

Invokes a method of the service.

@param request
- The invocation request
@return the return value
@throws IllegalInvocationException
if the request does not match the service
@throws InvocationTargetException
if an Exception is thrown during execution


public void setSelection(String[] selection) {
		for (String sel : selection) {
			for (int j = 0; j < mItems.length; ++j) {
				if (mItems[j].equals(sel)) {
					mSelection[j] = true;
				}
			}
		}

		refreshDisplayValue();
	}

public void setSelection ( String [ ] selection ) { for ( String sel : selection ) { for ( int j = 0 ; j < mItems . length ; ++ j ) { if ( mItems [ j ] . equals ( sel ) ) { mSelection [ j ] = true ; } } } refreshDisplayValue ( ) ; }

Sets the selected options based on an array of string.

@param selection

Sets the selected options based on an array of string .


public void setSelection(int[] selectedIndicies) {
		for (int index : selectedIndicies) {
			if (index >= 0 && index < mSelection.length) {
				mSelection[index] = true;
			} else {
				throw new IllegalArgumentException("Index " + index + " is out of bounds.");
			}
		}

		refreshDisplayValue();
	}

public
void
setSelection
(
int
[
]
selectedIndicies
)
{
for
(
int
index
:
selectedIndicies
)
{
if
(
index
>=
0
&&
index
<
mSelection
.
length
)
{
mSelection
[
index
]
=
true
;
}
else
{
throw
new
IllegalArgumentException
(
"Index "
+
index
+
" is out of bounds."
)
;
}
}
refreshDisplayValue
(
)
;
}

Sets the selected options based on an array of positions.

@param selectedIndicies

Sets the selected options based on an array of positions .


public List<String> getSelectedStrings() {
		List<String> selection = new LinkedList<String>();
		for (int i = 0; i < mItems.length; ++i) {
			if (mSelection[i]) {
				selection.add(mItems[i]);
			}
		}
		return selection;
	}

public List < String > getSelectedStrings ( ) { List < String > selection = new LinkedList < String > ( ) ; for ( int i = 0 ; i < mItems . length ; ++ i ) { if ( mSelection [ i ] ) { selection . add ( mItems [ i ] ) ; } } return selection ; }

Returns a list of strings, one for each selected item.

@return

Returns a list of strings one for each selected item .


public List<Integer> getSelectedIndicies() {
		List<Integer> selection = new LinkedList<Integer>();
		for (int i = 0; i < mItems.length; ++i) {
			if (mSelection[i]) {
				selection.add(i);
			}
		}
		return selection;
	}

public List < Integer > getSelectedIndicies ( ) { List < Integer > selection = new LinkedList < Integer > ( ) ; for ( int i = 0 ; i < mItems . length ; ++ i ) { if ( mSelection [ i ] ) { selection . add ( i ) ; } } return selection ; }

Returns a list of positions, one for each selected item.

@return

Returns a list of positions one for each selected item .


public void onRefresh() {
        mViewContainer.removeAllViews();
        for (ProfileField<?> field : mFieldsToShow) {
            View child = mParent.createViewFor(field, mViewContainer);
            mViewContainer.addView(child);
        }
    }

public void onRefresh ( ) { mViewContainer . removeAllViews ( ) ; for ( ProfileField < ? > field : mFieldsToShow ) { View child = mParent . createViewFor ( field , mViewContainer ) ; mViewContainer . addView ( child ) ; } }

Refreshes the values of displayed fields.

Refreshes the values of displayed fields .


public void shutdown() {
		synchronized (this) {
			if (mShutdown) {
				return;
			}

			for (AppServiceProxy p : mProxies.values()) {
				if (p.isConnected()) {
					mContext.unbindService(p);
					mProxies.remove(p);
				}
			}

			mShutdown = true;
		}
	}

public void shutdown ( ) { synchronized ( this ) { if ( mShutdown ) { return ; } for ( AppServiceProxy p : mProxies . values ( ) ) { if ( p . isConnected ( ) ) { mContext . unbindService ( p ) ; mProxies . remove ( p ) ; } } mShutdown = true ; } }

Unbinds all proxies available in caches and prevents the creation of new
ones.

Unbinds all proxies available in caches and prevents the creation of new ones .


private void insertNewLine() throws SAXException
	{
		try
		{
			writer.write(System.getProperty("line.separator"));
		}
		catch (final IOException e)
		{
			throw new SAXException("I/O error", e);
		}
	}

private
void
insertNewLine
(
)
throws
SAXException
{
try
{
writer
.
write
(
System
.
getProperty
(
"line.separator"
)
)
;
}
catch
(
final
IOException
e
)
{
throw
new
SAXException
(
"I/O error"
,
e
)
;
}
}

Insert a new line to the writer

@throws SAXException
any SAX exception, possibly wrapping another exception


private void writeToBuffer() throws SAXException
	{
		if (stringBuilder == null)
		{
			return;
		}
		final String string = stringBuilder.toString().trim();
		write(string);
		stringBuilder = null;
	}

private void writeToBuffer ( ) throws SAXException { if ( stringBuilder == null ) { return ; } final String string = stringBuilder . toString ( ) . trim ( ) ; write ( string ) ; stringBuilder = null ; }

Write to buffer.

@throws SAXException
any SAX exception, possibly wrapping another exception


public static <T> String toJsonQuietly(final T object)
	{
		try
		{
			return ObjectToJsonExtensions.toJson(object);
		}
		catch (final JsonProcessingException e)
		{
			log.log(Level.SEVERE,
				"An error occured when converting object to String.\nGiven object:"
					+ object.toString() + "\n",
				e);
		}
		return null;
	}

Creates from the given Object a json string. Note if an exception occurs null will be
returned.

@param <T>
the generic type of the given argument
@param object
the object.
@return the json string or null if an error occured by parsing.

Creates from the given Object a json string . Note if an exception occurs null will be returned .


protected static <C extends Component<C, I>, I extends IInterface> void load(final Context context, final Descriptor<C, I> descriptor, final ConnectionCallback<C> callback) {

		Utils.notNull(context, "context must not be null");
		Utils.notNull(descriptor, "context must not be null");

		if (AccessTokenManager.get(context).hasToken()) {
			bindToService(context, descriptor, callback);
		} else {
			AccessTokenManager.get(context).requireAccessToken(context, new AccessTokenManager.RegistrationCallback() {

				@Override
				public void onRegistrationSuccessful() {
					Log.d("Component" , "Access Toekn: " + descriptor);
					bindToService(context, descriptor, callback);
				}

				@Override
				public void onRegistrationError(SPFError errorMsg) {
					callback.onError(errorMsg);
				}
			});
		}

	}

protected
static
<
C
extends
Component
<
C
,
I
>
,
I
extends
IInterface
>
void
load
(
final
Context
context
,
final
Descriptor
<
C
,
I
>
descriptor
,
final
ConnectionCallback
<
C
>
callback
)
{
Utils
.
notNull
(
context
,
"context must not be null"
)
;
Utils
.
notNull
(
descriptor
,
"context must not be null"
)
;
if
(
AccessTokenManager
.
get
(
context
)
.
hasToken
(
)
)
{
bindToService
(
context
,
descriptor
,
callback
)
;
}
else
{
AccessTokenManager
.
get
(
context
)
.
requireAccessToken
(
context
,
new
AccessTokenManager
.
RegistrationCallback
(
)
{
@
Override
public
void
onRegistrationSuccessful
(
)
{
Log
.
d
(
"Component"
,
"Access Toekn: "
+
descriptor
)
;
bindToService
(
context
,
descriptor
,
callback
)
;
}
@
Override
public
void
onRegistrationError
(
SPFError
errorMsg
)
{
callback
.
onError
(
errorMsg
)
;
}
}
)
;
}
}

Loads a local component asynchronously.

@param context
- the context to use to bind to the service
@param descriptor
- a {@link Descriptor} to handle the creation of the
component;
@param callback
- the callback to be notified when the service is available
@param <C>
the type of the Component concrete implementation
@param <I>
the type of the AIDL interface that is wrapped by the
component

Loads a local component asynchronously .


private static <C extends Component<C, I>, I extends IInterface> void bindToService(final Context context, final Descriptor<C, I> descriptor, final ConnectionCallback<C> callback) {

		Intent intent = new Intent();
		intent.setComponent(SPFInfo.getSPFServiceComponentName());
		intent.setAction(descriptor.getActionName());

		ServiceConnection connection = new ServiceConnection() {

			@Override
			public void onServiceConnected(ComponentName name, IBinder binder) {
				I service = descriptor.castInterface(binder);
				C instance = descriptor.createInstance(context, service, this, callback);
				callback.onServiceReady(instance);
			}

			@Override
			public void onServiceDisconnected(ComponentName name) {
				callback.onDisconnect();
			}
		};

		if (!context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
			callback.onError(new SPFError(SPFError.SPF_NOT_INSTALLED_ERROR_CODE));
		}
	}

private static < C extends Component < C , I > , I extends IInterface > void bindToService ( final Context context , final Descriptor < C , I > descriptor , final ConnectionCallback < C > callback ) { Intent intent = new Intent ( ) ; intent . setComponent ( SPFInfo . getSPFServiceComponentName ( ) ) ; intent . setAction ( descriptor . getActionName ( ) ) ; ServiceConnection connection = new ServiceConnection ( ) { @ Override public void onServiceConnected ( ComponentName name , IBinder binder ) { I service = descriptor . castInterface ( binder ) ; C instance = descriptor . createInstance ( context , service , this , callback ) ; callback . onServiceReady ( instance ) ; } @ Override public void onServiceDisconnected ( ComponentName name ) { callback . onDisconnect ( ) ; } } ; if ( ! context . bindService ( intent , connection , Context . BIND_AUTO_CREATE ) ) { callback . onError ( new SPFError ( SPFError . SPF_NOT_INSTALLED_ERROR_CODE ) ) ; } }

Performs the binding to the remote service

@param context
- the context used to bind to the service
@param descriptor
- the {@link Descriptor} to handle the service
@param callback
- the callback to notify of the service availability


public void disconnect() {
		try {
			mContext.unbindService(mConnection);
		} catch (Exception e) {
			Log.w(getClass().getSimpleName(), "Exception unbinding from service: ", e);
		}
	}

public
void
disconnect
(
)
{
try
{
mContext
.
unbindService
(
mConnection
)
;
}
catch
(
Exception
e
)
{
Log
.
w
(
getClass
(
)
.
getSimpleName
(
)
,
"Exception unbinding from service: "
,
e
)
;
}
}

Disconnects the component from the remote service.

@see Context#unbindService(ServiceConnection)

Disconnects the component from the remote service .


protected void handleError(SPFError err) {
		if (err.codeEquals(SPFError.TOKEN_NOT_VALID_ERROR_CODE)) {
			AccessTokenManager.get(mContext).invalidateToken();
		}
		mCallback.onError(err);
	}

protected void handleError ( SPFError err ) { if ( err . codeEquals ( SPFError . TOKEN_NOT_VALID_ERROR_CODE ) ) { AccessTokenManager . get ( mContext ) . invalidateToken ( ) ; } mCallback . onError ( err ) ; }

Performs common error handling operations. Subclasses may override it to
provide specific behavior.

@param err

Performs common error handling operations . Subclasses may override it to provide specific behavior .


public void refreshTriggers(List<SPFTrigger> triggers2) {
		triggers.clear();
		for (SPFTrigger trg : triggers2) {
			triggers.put(trg.getId(), trg);
		}
	}

public void refreshTriggers ( List < SPFTrigger > triggers2 ) { triggers . clear ( ) ; for ( SPFTrigger trg : triggers2 ) { triggers . put ( trg . getId ( ) , trg ) ; } }

Update the current set of triggers with the given list.

@param triggers2

Update the current set of triggers with the given list .


boolean addPersona(SPFPersona persona) {
		SQLiteDatabase db = getWritableDatabase();
		String table = Contract.TABLE_PERSONAS;
		String nullColumnHack = null;
		ContentValues values = new ContentValues();
		values.put(Contract.COLUMN_PERSONA, persona.getIdentifier());
		if (db.insert(table, nullColumnHack, values) > 0) {
			// copy the unique identifier
			ProfileFieldContainer pfc = getProfileFieldBulk(SPFPersona.getDefault(), ProfileField.IDENTIFIER);
			String id = pfc.getFieldValue(ProfileField.IDENTIFIER);
			if (setValue(ProfileField.IDENTIFIER.getIdentifier(), id, persona.getIdentifier())) {
				addCircleToFieldsInternal(DefaultCircles.PUBLIC, ProfileField.IDENTIFIER, persona, db);
				addCircleToFieldsInternal(DefaultCircles.PUBLIC, ProfileField.DISPLAY_NAME, persona, db);
				return true;
			} else {
				removePersona(persona);
				return false;
			}
		}
		return false;
	}

boolean
addPersona
(
SPFPersona
persona
)
{
SQLiteDatabase
db
=
getWritableDatabase
(
)
;
String
table
=
Contract
.
TABLE_PERSONAS
;
String
nullColumnHack
=
;
ContentValues
values
=
new
ContentValues
(
)
;
values
.
put
(
Contract
.
COLUMN_PERSONA
,
persona
.
getIdentifier
(
)
)
;
if
(
db
.
insert
(
table
,
nullColumnHack
,
values
)
>
0
)
{
// copy the unique identifier
ProfileFieldContainer
pfc
=
getProfileFieldBulk
(
SPFPersona
.
getDefault
(
)
,
ProfileField
.
IDENTIFIER
)
;
String
id
=
pfc
.
getFieldValue
(
ProfileField
.
IDENTIFIER
)
;
if
(
setValue
(
ProfileField
.
IDENTIFIER
.
getIdentifier
(
)
,
id
,
persona
.
getIdentifier
(
)
)
)
{
addCircleToFieldsInternal
(
DefaultCircles
.
PUBLIC
,
ProfileField
.
IDENTIFIER
,
persona
,
db
)
;
addCircleToFieldsInternal
(
DefaultCircles
.
PUBLIC
,
ProfileField
.
DISPLAY_NAME
,
persona
,
db
)
;
return
true
;
}
else
{
removePersona
(
persona
)
;
return
false
;
}
}
return
false
;
}

Creates a new SPFPersona.

@param persona
- the {@link SPFPersona} to add.


boolean removePersona(SPFPersona persona) {
		SQLiteDatabase db = getWritableDatabase();
		if (persona.getIdentifier().equals("default")) {
			return false;
		}

		String table = Contract.TABLE_PERSONAS;
		String selection = Contract.COLUMN_PERSONA + " = ?";
		String[] selectionArgs = { persona.getIdentifier() };
		if (db.delete(table, selection, selectionArgs) > 0) {
			deleteFieldsOf(persona, db);
			deleteVisibilityOf(persona, db);
		}
		return true;
	}

boolean
removePersona
(
SPFPersona
persona
)
{
SQLiteDatabase
db
=
getWritableDatabase
(
)
;
if
(
persona
.
getIdentifier
(
)
.
equals
(
"default"
)
)
{
return
false
;
}
String
table
=
Contract
.
TABLE_PERSONAS
;
String
selection
=
Contract
.
COLUMN_PERSONA
+
" = ?"
;
String
[
]
selectionArgs
=
{
persona
.
getIdentifier
(
)
}
;
if
(
db
.
delete
(
table
,
selection
,
selectionArgs
)
>
0
)
{
deleteFieldsOf
(
persona
,
db
)
;
deleteVisibilityOf
(
persona
,
db
)
;
}
return
true
;
}

Delete a SPFPersona. All the information related to the specified persona
will be erased.

@param persona
- the {@link SPFPersona} to remove

Delete a SPFPersona . All the information related to the specified persona will be erased .


public boolean registerService(SPFServiceDescriptor descriptor) {
		String appId = descriptor.getAppIdentifier();
		String serviceName = descriptor.getServiceName();

		for (String verb : descriptor.getConsumedVerbs()) {
			if (!registerServiceInternal(verb, serviceName, appId)) {
				return false;
			}

			Log.v(TAG, "Registered service as Activity consumer: " + descriptor.getServiceName());
		}

		return true;
	}

Registers the capabilities of a service to consume activities. If the
descriptor doesn't declare the service as capable of handling activities,
no action will be performed.

@param descriptor
- the descriptor of the service to register
@return true if the service was registered

Registers the capabilities of a service to consume activities . If the descriptor doesn t declare the service as capable of handling activities no action will be performed .


AppAuth getAppAuthorizationByAppId(String appId) {
		String where = Contract.COLUMN_APP_IDENTIFIER + " = ?";
		String args[] = { appId };
		Cursor c = mRegistryTable.getReadableDatabase().query(Contract.TABLE_NAME, null, where, args, null, null, null);
		AppAuth auth = null;
		if (c.moveToFirst()) {
			auth = appAuthFromCursor(c);
		}
		c.close();
		return auth;
	}

AppAuth
getAppAuthorizationByAppId
(
String
appId
)
{
String
where
=
Contract
.
COLUMN_APP_IDENTIFIER
+
" = ?"
;
String
args
[
]
=
{
appId
}
;
Cursor
c
=
mRegistryTable
.
getReadableDatabase
(
)
.
query
(
Contract
.
TABLE_NAME
,
,
where
,
args
,
,
,
)
;
AppAuth
auth
=
;
if
(
c
.
moveToFirst
(
)
)
{
auth
=
appAuthFromCursor
(
c
)
;
}
c
.
close
(
)
;
return
auth
;
}

Retrieves an appauth given the identifier of an application

@param appId
- the Id of the application
@return the appAuth of the application, or null if the app is not
installed


public String registerApplication(AppDescriptor descriptor, SPFPersona persona) {
		String token = mTokenGenerator.generateAccessToken();

		ContentValues cv = new ContentValues();
		cv.put(Contract.COLUMN_APP_NAME, descriptor.getAppName());
		cv.put(Contract.COLUMN_ACCESS_TOKEN, token);
		cv.put(Contract.COLUMN_APP_IDENTIFIER, descriptor.getAppIdentifier());
		cv.put(Contract.COLUMN_PERMISSION_CODE, descriptor.getPermissionCode());
		cv.put(Contract.COLUMN_PERSONA, persona.getIdentifier());

		SQLiteDatabase db = mRegistryTable.getWritableDatabase();
		if (db.insert(Contract.TABLE_NAME, null, cv) == -1) {
			return null; // TODO handle insertion error
		}

		return token;
	}

public
String
registerApplication
(
AppDescriptor
descriptor
,
SPFPersona
persona
)
{
String
token
=
mTokenGenerator
.
generateAccessToken
(
)
;
ContentValues
cv
=
new
ContentValues
(
)
;
cv
.
put
(
Contract
.
COLUMN_APP_NAME
,
descriptor
.
getAppName
(
)
)
;
cv
.
put
(
Contract
.
COLUMN_ACCESS_TOKEN
,
token
)
;
cv
.
put
(
Contract
.
COLUMN_APP_IDENTIFIER
,
descriptor
.
getAppIdentifier
(
)
)
;
cv
.
put
(
Contract
.
COLUMN_PERMISSION_CODE
,
descriptor
.
getPermissionCode
(
)
)
;
cv
.
put
(
Contract
.
COLUMN_PERSONA
,
persona
.
getIdentifier
(
)
)
;
SQLiteDatabase
db
=
mRegistryTable
.
getWritableDatabase
(
)
;
if
(
db
.
insert
(
Contract
.
TABLE_NAME
,
,
cv
)
==
1
)
{
return
;
// TODO handle insertion error
}
return
token
;
}

Low level method to register applications. It will not validate the
descriptor given as parameter.

@param descriptor
@param persona
@return - the token to give back.

Low level method to register applications . It will not validate the descriptor given as parameter .


public boolean unregisterApplication(String appIdentifier) {
		String where = Contract.COLUMN_APP_IDENTIFIER + " = ?";
		String[] whereArgs = { appIdentifier };
		if (mRegistryTable.getWritableDatabase().delete(Contract.TABLE_NAME, where, whereArgs) == 0) {
			return false;
		}

		if (SPF.get().getServiceRegistry().unregisterAllServicesOfApp(appIdentifier)) {
			Intent i = new Intent(DEREGISTRATION_INTENT);
			i.putExtra(DEREGISTERED_APP, appIdentifier);
			mContext.sendBroadcast(i);
			return true;
		}

		return false;
	}

public
boolean
unregisterApplication
(
String
appIdentifier
)
{
String
where
=
Contract
.
COLUMN_APP_IDENTIFIER
+
" = ?"
;
String
[
]
whereArgs
=
{
appIdentifier
}
;
if
(
mRegistryTable
.
getWritableDatabase
(
)
.
delete
(
Contract
.
TABLE_NAME
,
where
,
whereArgs
)
==
0
)
{
return
false
;
}
if
(
SPF
.
get
(
)
.
getServiceRegistry
(
)
.
unregisterAllServicesOfApp
(
appIdentifier
)
)
{
Intent
i
=
new
Intent
(
DEREGISTRATION_INTENT
)
;
i
.
putExtra
(
DEREGISTERED_APP
,
appIdentifier
)
;
mContext
.
sendBroadcast
(
i
)
;
return
true
;
}
return
false
;
}

To be called from application uninstall monitor

@param appIdentifier


public SPFPersona getPersonaOf(String appIdentifier) {
		SQLiteDatabase db = mRegistryTable.getReadableDatabase();
		String table = Contract.TABLE_NAME;
		String[] columns = { Contract.COLUMN_PERSONA };
		String selection = Contract.COLUMN_APP_IDENTIFIER + " = ? ";
		String[] selectionArgs = { appIdentifier };
		String groupBy = null;
		String having = null;
		String orderBy = null;
		Cursor c = db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
		if (c.moveToNext()) {
			String persona = c.getString(c.getColumnIndex(Contract.COLUMN_PERSONA));
			return new SPFPersona(persona);
		}

		c.close();
		return SPFPersona.DEFAULT;
	}

public
SPFPersona
getPersonaOf
(
String
appIdentifier
)
{
SQLiteDatabase
db
=
mRegistryTable
.
getReadableDatabase
(
)
;
String
table
=
Contract
.
TABLE_NAME
;
String
[
]
columns
=
{
Contract
.
COLUMN_PERSONA
}
;
String
selection
=
Contract
.
COLUMN_APP_IDENTIFIER
+
" = ? "
;
String
[
]
selectionArgs
=
{
appIdentifier
}
;
String
groupBy
=
;
String
having
=
;
String
orderBy
=
;
Cursor
c
=
db
.
query
(
table
,
columns
,
selection
,
selectionArgs
,
groupBy
,
having
,
orderBy
)
;
if
(
c
.
moveToNext
(
)
)
{
String
persona
=
c
.
getString
(
c
.
getColumnIndex
(
Contract
.
COLUMN_PERSONA
)
)
;
return
new
SPFPersona
(
persona
)
;
}
c
.
close
(
)
;
return
SPFPersona
.
DEFAULT
;
}

Returns the SPFPersona associated to the specified application. If the
application does not exist returns the default SPFPersona.

@param appIdentifier
- the identifier of the application
@return a SPFPersona

Returns the SPFPersona associated to the specified application . If the application does not exist returns the default SPFPersona .


void onMessageReceived(final WfdMessage msg) {
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                if (msg.getReceiverId().equals(myIdentifier)) {
                    handle(msg);
                } else {
                    route(msg);
                }
            }
        });
    }

void onMessageReceived ( final WfdMessage msg ) { threadPool . execute ( new Runnable ( ) { @ Override public void run ( ) { if ( msg . getReceiverId ( ) . equals ( myIdentifier ) ) { handle ( msg ) ; } else { route ( msg ) ; } } } ) ; }


public void addClientIfNotPresent(DeviceGuiElement device) {
        boolean add = true;
        for (DeviceGuiElement element : clients) {
            if (element != null
                    && element.getName().equals(device.getName())
                    && element.getAddress().equals(device.getAddress())) {
                add = false; //already in the list
            }
        }

        if (add) {
            clients.add(device);
        }
    }

public
void
addClientIfNotPresent
(
DeviceGuiElement
device
)
{
boolean
add
=
true
;
for
(
DeviceGuiElement
element
:
clients
)
{
if
(
element
!=
&&
element
.
getName
(
)
.
equals
(
device
.
getName
(
)
)
&&
element
.
getAddress
(
)
.
equals
(
device
.
getAddress
(
)
)
)
{
add
=
false
;
//already in the list
}
}
if
(
add
)
{
clients
.
add
(
device
)
;
}
}

Method to add a client inside the list in a secure way.
The client is added only if isn't already inside the list.

@param device {@link DeviceGuiElement} to add.

Method to add a client inside the list in a secure way . The client is added only if isn t already inside the list .


public void connect() {
        if (!mMiddleware.isConnected()) {
            mMiddleware.connect();
        }

        if (!mNotificationManager.isRunning()) {
            mNotificationManager.start();
        }

        if (mAdvertiseManager.isAdvertisingEnabled()) {
            mMiddleware.registerAdvertisement(mAdvertiseManager.generateAdvProfile().toJSON(), 10000);
        }
    }

public void connect ( ) { if ( ! mMiddleware . isConnected ( ) ) { mMiddleware . connect ( ) ; } if ( ! mNotificationManager . isRunning ( ) ) { mNotificationManager . start ( ) ; } if ( mAdvertiseManager . isAdvertisingEnabled ( ) ) { mMiddleware . registerAdvertisement ( mAdvertiseManager . generateAdvProfile ( ) . toJSON ( ) , 10000 ) ; } }


public <E> E getFieldValue(ProfileField<E> field) {
        if (field == null) {
            throw new NullPointerException();
        }

        String val = mFields.getString(field.getIdentifier());
        return val == null ? null : ProfileFieldConverter.forField(field).fromStorageString(val);
    }

public < E > E getFieldValue ( ProfileField < E > field ) { if ( field == null ) { throw new NullPointerException ( ) ; } String val = mFields . getString ( field . getIdentifier ( ) ) ; return val == null ? null : ProfileFieldConverter . forField ( field ) . fromStorageString ( val ) ; }

Gets the value of a field from the container

@param field - the field whose value to retrieve

@return the value of the field, or null if the container doesn't have a value for such field


public boolean isModified() {
        for (String key : mStatus.keySet()) {
            FieldStatus status = getStatus(key);
            if (status == FieldStatus.DELETED || status == FieldStatus.MODIFIED) {
                return true;
            }
        }

        return false;
    }

public boolean isModified ( ) { for ( String key : mStatus . keySet ( ) ) { FieldStatus status = getStatus ( key ) ; if ( status == FieldStatus . DELETED || status == FieldStatus . MODIFIED ) { return true ; } } return false ; }

Returns whether at least one field in the container has been modified

@return true if at least the value of one field in the container has been modified, false
otherwise


public void stopSearch(int tag) {
		String queryId = mTagToId.get(tag);
		mTagToId.delete(tag);
		if (queryId != null && mCallbacks.remove(queryId) != null) {
			mSearchInterface.stopSearch(queryId);
		}
	}

public void stopSearch ( int tag ) { String queryId = mTagToId . get ( tag ) ; mTagToId . delete ( tag ) ; if ( queryId != null && mCallbacks . remove ( queryId ) != null ) { mSearchInterface . stopSearch ( queryId ) ; } }

Stops a previously registered search request performed by the
application. The application must provide the tag it registered the
search with. The callback associated to the search does not receive any
further notification.

@param tag
- the tag used to register the search.

Stops a previously registered search request performed by the application . The application must provide the tag it registered the search with . The callback associated to the search does not receive any further notification .


public void stopAllSearches() {
		mTagToId.clear();
		String[] queryIds = mCallbacks.keySet().toArray(new String[]{});
		mCallbacks.clear();
		for (String queryId : queryIds) {
			mSearchInterface.stopSearch(queryId);
		}
	}

public void stopAllSearches ( ) { mTagToId . clear ( ) ; String [ ] queryIds = mCallbacks . keySet ( ) . toArray ( new String [ ] { } ) ; mCallbacks . clear ( ) ; for ( String queryId : queryIds ) { mSearchInterface . stopSearch ( queryId ) ; } }

Stops all searches registered by the application.

@see SPFSearch#stopSearch(int)

Stops all searches registered by the application .


public SPFPerson lookup(String identifier) {
		boolean isReachable = mSearchInterface.lookup(identifier);
		if (isReachable) {
			return new SPFPerson(identifier);
		} else {
			return null;
		}
	}

public SPFPerson lookup ( String identifier ) { boolean isReachable = mSearchInterface . lookup ( identifier ) ; if ( isReachable ) { return new SPFPerson ( identifier ) ; } else { return null ; } }

Allows to retrieve a reference to a remote person given its identifier.
This reference is valid until the given person is reachable from the
proximity middleware.

@param identifier
@return

Allows to retrieve a reference to a remote person given its identifier . This reference is valid until the given person is reachable from the proximity middleware .


public ProfileFieldContainer getProfileFieldBulk(PersonAuth auth, SPFPersona persona, String[] fields) {
		return mProfileTable.getProfileFieldBulk(persona, fields, auth);
	}

public ProfileFieldContainer getProfileFieldBulk ( PersonAuth auth , SPFPersona persona , String [ ] fields ) { return mProfileTable . getProfileFieldBulk ( persona , fields , auth ) ; }

Method for proximity interface to provide access to local profile to
remote spf instances

@param auth
- the {@link PersonAuth} of the sender of the request
@param persona
@param fields
- the identifiers of the list of fields to read
@return a {@link ProfileFieldContainer} with the value of read fields, if
accessible.


public BaseInfo getBaseInfo(SPFPersona persona) {
		ProfileFieldContainer pfc = getProfileFieldBulk(persona, ProfileField.IDENTIFIER, ProfileField.DISPLAY_NAME);
		return new BaseInfo(pfc.getFieldValue(ProfileField.IDENTIFIER), pfc.getFieldValue(ProfileField.DISPLAY_NAME));
	}

public BaseInfo getBaseInfo ( SPFPersona persona ) { ProfileFieldContainer pfc = getProfileFieldBulk ( persona , ProfileField . IDENTIFIER , ProfileField . DISPLAY_NAME ) ; return new BaseInfo ( pfc . getFieldValue ( ProfileField . IDENTIFIER ) , pfc . getFieldValue ( ProfileField . DISPLAY_NAME ) ) ; }

Returns the display_name of the user. If there is no display_name, the
method returns its identifier.

@param persona
- the {@link SPFPersona} to read.
@return the {@link BaseInfo} of the given persona

Returns the display_name of the user . If there is no display_name the method returns its identifier .


public static NodeList getNodeList(final String xml, final String xpathExpression)
		throws XPathExpressionException, ParserConfigurationException, SAXException, IOException
	{
		final DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
		domFactory.setNamespaceAware(true);
		final DocumentBuilder builder = domFactory.newDocumentBuilder();
		final Document doc = builder.parse(xml);
		final XPath xpath = XPathFactory.newInstance().newXPath();
		final XPathExpression expr = xpath.compile(xpathExpression);

		final Object result = expr.evaluate(doc, XPathConstants.NODESET);
		final NodeList nodes = (NodeList)result;
		return nodes;
	}

public static NodeList getNodeList ( final String xml , final String xpathExpression ) throws XPathExpressionException , ParserConfigurationException , SAXException , IOException { final DocumentBuilderFactory domFactory = DocumentBuilderFactory . newInstance ( ) ; domFactory . setNamespaceAware ( true ) ; final DocumentBuilder builder = domFactory . newDocumentBuilder ( ) ; final Document doc = builder . parse ( xml ) ; final XPath xpath = XPathFactory . newInstance ( ) . newXPath ( ) ; final XPathExpression expr = xpath . compile ( xpathExpression ) ; final Object result = expr . evaluate ( doc , XPathConstants . NODESET ) ; final NodeList nodes = ( NodeList ) result ; return nodes ; }

Gets the node list from the given xml file and the given xpath expression.

@param xml
the xml file as string.
@param xpathExpression
the xpath expression as string.
@return the node list
@throws XPathExpressionException
the x path expression exception
@throws ParserConfigurationException
the parser configuration exception
@throws SAXException
the sAX exception
@throws IOException
Signals that an I/O exception has occurred.

Gets the node list from the given xml file and the given xpath expression .


public static <E> E onMainThread(Class<E> callbackInterface, final E callback) {
		Utils.notNull(callbackInterface, "callbackInterface must not be null");
		Utils.notNull(callback, "callback must not be null");

		final Handler handler = new Handler(Looper.getMainLooper());
		final String tag = callback.getClass().getSimpleName();

		Object proxy = Proxy.newProxyInstance(callbackInterface.getClassLoader(), new Class<?>[] { callbackInterface }, new InvocationHandler() {

			@Override
			public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
				handler.post(new Runnable() {

					@Override
					public void run() {
						try {
							method.invoke(callback, args);
						} catch (IllegalAccessException e) {
							Log.e(tag, "Error executing method " + method.getName() + " on main thread.", e);
						} catch (IllegalArgumentException e) {
							Log.e(tag, "Error executing method " + method.getName() + " on main thread.", e);
						} catch (InvocationTargetException e) {
							Log.e(tag, "Error executing method " + method.getName() + " on main thread.", e);
						}
					}
				});

				return null;
			}
		});

		return callbackInterface.cast(proxy);
	}

public
static
<
E
>
E
onMainThread
(
Class
<
E
>
callbackInterface
,
final
E
callback
)
{
Utils
.
notNull
(
callbackInterface
,
"callbackInterface must not be null"
)
;
Utils
.
notNull
(
callback
,
"callback must not be null"
)
;
final
Handler
handler
=
new
Handler
(
Looper
.
getMainLooper
(
)
)
;
final
String
tag
=
callback
.
getClass
(
)
.
getSimpleName
(
)
;
Object
proxy
=
Proxy
.
newProxyInstance
(
callbackInterface
.
getClassLoader
(
)
,
new
Class
<
>
[
]
{
callbackInterface
}
,
new
InvocationHandler
(
)
{
@
Override
public
Object
invoke
(
Object
proxy
,
final
Method
method
,
final
Object
[
]
args
)
throws
Throwable
{
handler
.
post
(
new
Runnable
(
)
{
@
Override
public
void
run
(
)
{
try
{
method
.
invoke
(
callback
,
args
)
;
}
catch
(
IllegalAccessException
e
)
{
Log
.
e
(
tag
,
"Error executing method "
+
method
.
getName
(
)
+
" on main thread."
,
e
)
;
}
catch
(
IllegalArgumentException
e
)
{
Log
.
e
(
tag
,
"Error executing method "
+
method
.
getName
(
)
+
" on main thread."
,
e
)
;
}
catch
(
InvocationTargetException
e
)
{
Log
.
e
(
tag
,
"Error executing method "
+
method
.
getName
(
)
+
" on main thread."
,
e
)
;
}
}
}
)
;
return
;
}
}
)
;
return
callbackInterface
.
cast
(
proxy
)
;
}

Wraps a callback into a proxy that executes its methods on the main
thread. Return types are not supported, a method with return type other
than void always returns null when called on the proxy.

@param callbackInterface
- the interface of the callback.
@param callback
- the callback implementation
@return the proxy to execute methods on the main thread.

Wraps a callback into a proxy that executes its methods on the main thread . Return types are not supported a method with return type other than void always returns null when called on the proxy .


public PersonAuth getPersonAuthFrom(String receivedTkn) {
		if (receivedTkn.equals("")) {
			return PersonAuth.getPublicAuth();
		}

		String selection = RelationshipEntry.COLUMN_TKN + " = ? AND " + RelationshipEntry.COLUMN_REQUEST_STATUS + " = ?";
		String[] selectionArgs = { receivedTkn, Integer.toString(REQUEST_ACCEPTED) };
		String[] columns = { RelationshipEntry.COLUMN_USER_UUID };
		SQLiteDatabase db = getReadableDatabase();
		Cursor cursor = db.query(RelationshipEntry.TABLE_PERSON_AUTH, columns, selection, selectionArgs, /* groupBy */null, /* having */null, /* orderBy */
				null);

		PersonAuth auth;
		if (cursor.moveToNext()) {
			String uniqueIdentifier = cursor.getString(cursor.getColumnIndex(RelationshipEntry.COLUMN_USER_UUID));
			auth = generatePermissionFor(uniqueIdentifier, db);
		} else {
			auth = PersonAuth.getPublicAuth();
		}

		cursor.close();
		return auth;
	}

public
PersonAuth
getPersonAuthFrom
(
String
receivedTkn
)
{
if
(
receivedTkn
.
equals
(
""
)
)
{
return
PersonAuth
.
getPublicAuth
(
)
;
}
String
selection
=
RelationshipEntry
.
COLUMN_TKN
+
" = ? AND "
+
RelationshipEntry
.
COLUMN_REQUEST_STATUS
+
" = ?"
;
String
[
]
selectionArgs
=
{
receivedTkn
,
Integer
.
toString
(
REQUEST_ACCEPTED
)
}
;
String
[
]
columns
=
{
RelationshipEntry
.
COLUMN_USER_UUID
}
;
SQLiteDatabase
db
=
getReadableDatabase
(
)
;
Cursor
cursor
=
db
.
query
(
RelationshipEntry
.
TABLE_PERSON_AUTH
,
columns
,
selection
,
selectionArgs
,
/* groupBy */
,
/* having */
,
/* orderBy */
)
;
PersonAuth
auth
;
if
(
cursor
.
moveToNext
(
)
)
{
String
uniqueIdentifier
=
cursor
.
getString
(
cursor
.
getColumnIndex
(
RelationshipEntry
.
COLUMN_USER_UUID
)
)
;
auth
=
generatePermissionFor
(
uniqueIdentifier
,
db
)
;
}
else
{
auth
=
PersonAuth
.
getPublicAuth
(
)
;
}
cursor
.
close
(
)
;
return
auth
;
}

Call this method every time you receive a remote request.

@param receivedTkn
- may be null
@return

Call this method every time you receive a remote request .


public String createEntryForSentRequest(String targetUid, String password) throws GeneralSecurityException {
		// TODO Add it back later
		// if (entryExistsFor(targetUid) != REQUEST_NOT_EXIST) {
		// return ;
		// }

		String user_uuid = targetUid;
		String token = new IdentifierGenerator().generateAccessToken();

		int request_status = REQUEST_ACCEPTED;
		insertNewEntry(user_uuid, token, request_status);
		return TokenCipher.encryptToken(token, password);
	}

Creates a pending request associated to the target id.

@param targetUid
@return

Creates a pending request associated to the target id .


public boolean createEntryForReceivedRequest(ContactRequest fr) {
		String user_uuid = fr.getUserIdentifier();
		String receive_token = fr.getAccessToken();
		int request_status = REQUEST_PENDING;
		if (insertNewEntry(user_uuid, receive_token, request_status)) {
			return true;
		}
		return false;
	}

public boolean createEntryForReceivedRequest ( ContactRequest fr ) { String user_uuid = fr . getUserIdentifier ( ) ; String receive_token = fr . getAccessToken ( ) ; int request_status = REQUEST_PENDING ; if ( insertNewEntry ( user_uuid , receive_token , request_status ) ) { return true ; } return false ; }

Creates a pending request with the information contained in the message.

@param fr
@return

Creates a pending request with the information contained in the message .


public int entryExistsFor(String userUID) {
		String selection = RelationshipEntry.COLUMN_USER_UUID + " = ?";
		String[] selectionArgs = { userUID };
		String[] columns = { RelationshipEntry.COLUMN_REQUEST_STATUS };
		SQLiteDatabase db = getReadableDatabase();
		Cursor cursor = db.query(RelationshipEntry.TABLE_PERSON_AUTH, columns, selection, selectionArgs, /* groupBy */null, /* having */null, /* orderBy */
				null);
		if (cursor.moveToNext()) {
			return cursor.getInt(cursor.getColumnIndex(RelationshipEntry.COLUMN_REQUEST_STATUS));
		}
		cursor.close();
		return REQUEST_NOT_EXIST;
	}

public
int
entryExistsFor
(
String
userUID
)
{
String
selection
=
RelationshipEntry
.
COLUMN_USER_UUID
+
" = ?"
;
String
[
]
selectionArgs
=
{
userUID
}
;
String
[
]
columns
=
{
RelationshipEntry
.
COLUMN_REQUEST_STATUS
}
;
SQLiteDatabase
db
=
getReadableDatabase
(
)
;
Cursor
cursor
=
db
.
query
(
RelationshipEntry
.
TABLE_PERSON_AUTH
,
columns
,
selection
,
selectionArgs
,
/* groupBy */
,
/* having */
,
/* orderBy */
)
;
if
(
cursor
.
moveToNext
(
)
)
{
return
cursor
.
getInt
(
cursor
.
getColumnIndex
(
RelationshipEntry
.
COLUMN_REQUEST_STATUS
)
)
;
}
cursor
.
close
(
)
;
return
REQUEST_NOT_EXIST
;
}

check if an entry for the specified user id exists. Returns the entry
state.

@param userUID
@return

check if an entry for the specified user id exists . Returns the entry state .


public boolean confirmRequest(String targetUID, String password) throws GeneralSecurityException, WrongPassphraseException {
		SQLiteDatabase db = getWritableDatabase();
		String table = RelationshipEntry.TABLE_PERSON_AUTH;
		String[] columns = { RelationshipEntry.COLUMN_TKN, RelationshipEntry.COLUMN_REQUEST_STATUS, RelationshipEntry.COLUMN_PASSWORD };
		String selection = RelationshipEntry.COLUMN_USER_UUID + " = ? ";
		String[] selectionArgs = { targetUID };
		String groupBy = null;
		String having = null;
		String orderBy = null;
		String limit = null;
		Cursor c = db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit);
		if (c.moveToNext()) {
			String token = c.getString(c.getColumnIndex(RelationshipEntry.COLUMN_TKN));
			String decryptedTkn = TokenCipher.decryptToken(token, password);
			if (decryptedTkn != null) {
				return commitConfirmation(targetUID, password, decryptedTkn);
			} else {
				return false;
			}
		}
		return false;
	}

public
boolean
confirmRequest
(
String
targetUID
,
String
password
)
throws
GeneralSecurityException
,
WrongPassphraseException
{
SQLiteDatabase
db
=
getWritableDatabase
(
)
;
String
table
=
RelationshipEntry
.
TABLE_PERSON_AUTH
;
String
[
]
columns
=
{
RelationshipEntry
.
COLUMN_TKN
,
RelationshipEntry
.
COLUMN_REQUEST_STATUS
,
RelationshipEntry
.
COLUMN_PASSWORD
}
;
String
selection
=
RelationshipEntry
.
COLUMN_USER_UUID
+
" = ? "
;
String
[
]
selectionArgs
=
{
targetUID
}
;
String
groupBy
=
;
String
having
=
;
String
orderBy
=
;
String
limit
=
;
Cursor
c
=
db
.
query
(
table
,
columns
,
selection
,
selectionArgs
,
groupBy
,
having
,
orderBy
,
limit
)
;
if
(
c
.
moveToNext
(
)
)
{
String
token
=
c
.
getString
(
c
.
getColumnIndex
(
RelationshipEntry
.
COLUMN_TKN
)
)
;
String
decryptedTkn
=
TokenCipher
.
decryptToken
(
token
,
password
)
;
if
(
decryptedTkn
!=
)
{
return
commitConfirmation
(
targetUID
,
password
,
decryptedTkn
)
;
}
else
{
return
false
;
}
}
return
false
;
}

Confirm a friendship request. the status of the entry associated with the
specified person, will be REQUEST_ACCEPTED

@param targetUID
- the unique identifier of the person
@throws WrongPassphraseException
@throws GeneralSecurityException

Confirm a friendship request . the status of the entry associated with the specified person will be REQUEST_ACCEPTED


@Override
  public void addClosingTag(String tagName)
  {
    _indent.dec();
    _xml.addXML(_indent.toString());
    _xml.addClosingTag(tagName);
    _xml.addXML("\n");
  }

@ Override public void addClosingTag ( String tagName ) { _indent . dec ( ) ; _xml . addXML ( _indent . toString ( ) ) ; _xml . addClosingTag ( tagName ) ; _xml . addXML ( "\n" ) ; }

Adds a closing tag

@param tagName the name of the closing tag to add


@Override
  public void addEmptyTag(String tagName)
  {
    _xml.addXML(_indent.toString());
    _xml.addEmptyTag(tagName);
    _xml.addXML("\n");
  }

@ Override public void addEmptyTag ( String tagName ) { _xml . addXML ( _indent . toString ( ) ) ; _xml . addEmptyTag ( tagName ) ; _xml . addXML ( "\n" ) ; }

Adds an empty tag

@param tagName the name of the empty tag to add


@Override
  public void addOpeningTag(String tagName, Map attributes)
  {
    _xml.addXML(_indent.toString());
    _xml.addOpeningTag(tagName, attributes);
    _xml.addXML("\n");
    _indent.inc();
  }

@ Override public void addOpeningTag ( String tagName , Map attributes ) { _xml . addXML ( _indent . toString ( ) ) ; _xml . addOpeningTag ( tagName , attributes ) ; _xml . addXML ( "\n" ) ; _indent . inc ( ) ; }

Adds an opening tag which contains the attributes specified. All the
properties will be turned into attributes.

@param tagName the name of the opening tag to add
@param attributes the attributes

Adds an opening tag which contains the attributes specified . All the properties will be turned into attributes .


public static boolean deleteFile(File file) throws IOException
  {
    if(!file.exists())
      return false;

    File[] files = file.listFiles();

    if(files != null)
    {
      for(int i = 0; i < files.length; i++)
      {
        File childFile = files[i];
        if(childFile.equals(file))
          continue;

        if(childFile.isDirectory())
          deleteFile(childFile);
        else
          childFile.delete();
      }
    }

    return file.delete();
  }

public static boolean deleteFile ( File file ) throws IOException { if ( ! file . exists ( ) ) return false ; File [ ] files = file . listFiles ( ) ; if ( files != null ) { for ( int i = 0 ; i < files . length ; i ++ ) { File childFile = files [ i ] ; if ( childFile . equals ( file ) ) continue ; if ( childFile . isDirectory ( ) ) deleteFile ( childFile ) ; else childFile . delete ( ) ; } } return file . delete ( ) ; }

Deletes the file provided. If it is a directory, recursively deletes a directory and its content.

@param file
@return true if the file was deleted, false
if didn't exist
@throws IOException

Deletes the file provided . If it is a directory recursively deletes a directory and its content .


public static File createTempDirectory(String namespace, String name) throws IOException
  {
    File dir = File.createTempFile(namespace, "");

    if(dir.exists())
      deleteFile(dir);

    createNewDirectory(dir);

    File tempDir = new File(dir, name);

    createNewDirectory(tempDir);

    return tempDir.getCanonicalFile();
  }

public static File createTempDirectory ( String namespace , String name ) throws IOException { File dir = File . createTempFile ( namespace , "" ) ; if ( dir . exists ( ) ) deleteFile ( dir ) ; createNewDirectory ( dir ) ; File tempDir = new File ( dir , name ) ; createNewDirectory ( tempDir ) ; return tempDir . getCanonicalFile ( ) ; }

Creates a temporary directory.

@param namespace
@param name      root name of the temporary directory
@return the temp dir
@throws IOException if there is a problem


@SuppressWarnings("unchecked")
  public static Object getProxiedObject(Object proxy)
  {
    if(Proxy.isProxyClass(proxy.getClass()))
    {
      InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy);
      if(invocationHandler instanceof ObjectProxy)
      {
        ObjectProxy objectProxy = (ObjectProxy) invocationHandler;
        // recursively fetch the proxy
        return getProxiedObject(objectProxy.getProxiedObject());
      }
      else
        return proxy;
    }
    else
      return proxy;

  }

@
SuppressWarnings
(
"unchecked"
)
public
static
Object
getProxiedObject
(
Object
proxy
)
{
if
(
Proxy
.
isProxyClass
(
proxy
.
getClass
(
)
)
)
{
InvocationHandler
invocationHandler
=
Proxy
.
getInvocationHandler
(
proxy
)
;
if
(
invocationHandler
instanceof
ObjectProxy
)
{
ObjectProxy
objectProxy
=
(
ObjectProxy
)
invocationHandler
;
// recursively fetch the proxy
return
getProxiedObject
(
objectProxy
.
getProxiedObject
(
)
)
;
}
else
return
proxy
;
}
else
return
proxy
;
}

Given a proxy returns the object proxied. If the object is not a proxy, then return the object
itself.

@param proxy
@return the proxied object (or proxy if not an object proxy)

Given a proxy returns the object proxied . If the object is not a proxy then return the object itself .


public static Class forName(Class clazz, ClassLoader classLoader)
    throws ClassNotFoundException, LinkageError
  {
    if(clazz == null)
      return null;

    if(classLoader == null)
    {
      classLoader = getDefaultClassLoader();
    }

    if(clazz.getClassLoader() == null || clazz.getClassLoader().equals(classLoader))
      return clazz;
    else
      return forName(clazz.getName(), classLoader);
  }

public static Class forName ( Class clazz , ClassLoader classLoader ) throws ClassNotFoundException , LinkageError { if ( clazz == null ) return null ; if ( classLoader == null ) { classLoader = getDefaultClassLoader ( ) ; } if ( clazz . getClassLoader ( ) == null || clazz . getClassLoader ( ) . equals ( classLoader ) ) return clazz ; else return forName ( clazz . getName ( ) , classLoader ) ; }

Convenient call to return a class in a different class loader... note that it will handle
correctly a class in the same class loader

@param clazz       the clazz you want in a different class loader
@param classLoader the class loader to use (may be null, which indicates the
default class loader)
@return Class instance for the supplied name
@throws ClassNotFoundException if the class was not found
@throws LinkageError           if the class file could not be loaded
@see Class#forName(String, boolean, ClassLoader)

Convenient call to return a class in a different class loader ... note that it will handle correctly a class in the same class loader


@SuppressWarnings("unchecked")
  public static String computeSignature(Method m)
  {
    StringBuilder sb = new StringBuilder();

    sb.append(m.getName()).append('(');
    Class[] parameterTypes = m.getParameterTypes();

    for (int i = 0; i < parameterTypes.length; i++)
    {
      if(i > 0)
        sb.append(',');
      Class parameterType = parameterTypes[i];
      sb.append(parameterType.getName());
    }
    sb.append(')');

    return sb.toString();
  }

@ SuppressWarnings ( "unchecked" ) public static String computeSignature ( Method m ) { StringBuilder sb = new StringBuilder ( ) ; sb . append ( m . getName ( ) ) . append ( ' ' ) ; Class [ ] parameterTypes = m . getParameterTypes ( ) ; for ( int i = 0 ; i < parameterTypes . length ; i ++ ) { if ( i > 0 ) sb . append ( ' ' ) ; Class parameterType = parameterTypes [ i ] ; sb . append ( parameterType . getName ( ) ) ; } sb . append ( ' ' ) ; return sb . toString ( ) ; }

Computes the signature of a method. Note that if 2 methods are declared
in different classes or interfaces then I1.m and I2.m are different but
they can still have the same signature...

@param m method
@return the signature (unique per method definition)

Computes the signature of a method . Note that if 2 methods are declared in different classes or interfaces then I1 . m and I2 . m are different but they can still have the same signature ...


private static OneWayMessageDigestCodec createWellKnownInstance(String algorithm,
                                                                  String password,
                                                                  OneWayCodec codec)
  {
    try
    {
      return new OneWayMessageDigestCodec(algorithm, password, codec);
    }
    catch(NoSuchAlgorithmException e)
    {
      throw new RuntimeException(e);
    }
    catch(CloneNotSupportedException e)
    {
      throw new RuntimeException(e);
    }
  }

private static OneWayMessageDigestCodec createWellKnownInstance ( String algorithm , String password , OneWayCodec codec ) { try { return new OneWayMessageDigestCodec ( algorithm , password , codec ) ; } catch ( NoSuchAlgorithmException e ) { throw new RuntimeException ( e ) ; } catch ( CloneNotSupportedException e ) { throw new RuntimeException ( e ) ; } }

This creates a well known instance.. the difference with the constructor
is that all exceptions are caught and rethrown as RuntimeExcpetion
because they should not happen.

@param algorithm
@param password
@param codec
@return the codec

This creates a well known instance .. the difference with the constructor is that all exceptions are caught and rethrown as RuntimeExcpetion because they should not happen .


public void reset()
  {
    _scheme = null;
    _userInfo = null;
    _host = null;
    _port = -1;
    _path = null;
    _query = new QueryBuilder();
    _fragment = null;
    _escapeFragment = true;
  }

public void reset ( ) { _scheme = null ; _userInfo = null ; _host = null ; _port = - 1 ; _path = null ; _query = new QueryBuilder ( ) ; _fragment = null ; _escapeFragment = true ; }

Call this method when you want to reset the internal string to start
from scratch again


public static URLBuilder createFromPath(String path)
  {
    URLBuilder res = new URLBuilder();
    res.setPath(path);
    return res;
  }

public static URLBuilder createFromPath ( String path ) { URLBuilder res = new URLBuilder ( ) ; res . setPath ( path ) ; return res ; }

Factory method from a path

@param path the path (will be url encoded!)
@return the builder


public static URL addQueryParameter(URL url, String name, String value)
  {
    URLBuilder ub = createFromURL(url);
    ub.addQueryParameter(name, value);
    return ub;
  }

public static URL addQueryParameter ( URL url , String name , String value ) { URLBuilder ub = createFromURL ( url ) ; ub . addQueryParameter ( name , value ) ; return ub ; }

Convenient call which adds a query parameter to the give url.

@param url the original URL: will stay unchanged
@param name the name of the query parameter
@param value the value of the query parameter
@return the new URL

Convenient call which adds a query parameter to the give url .


@Override
  public String getParameter(String name)
  {
    String[] params = getParameterValues(name);
    if(params == null)
      return null;

    return params[0];
  }

@ Override public String getParameter ( String name ) { String [ ] params = getParameterValues ( name ) ; if ( params == null ) return null ; return params [ 0 ] ; }

Get the first parameter given its name

@param name the name of the parameter
@return the first parameter


private void addQueryParameter(String name, String value)
  {
    if(_query.length() > 0)
      _query.append('&');
    _query.append(encode(name));
    _query.append('=');
    _query.append(encode(value));
  }

private void addQueryParameter ( String name , String value ) { if ( _query . length ( ) > 0 ) _query . append ( ' ' ) ; _query . append ( encode ( name ) ) ; _query . append ( ' ' ) ; _query . append ( encode ( value ) ) ; }

Add query parameter to query string.

@param name
@param value


public void addParameters(Map<String, String[]> parameters)
  {
    for(Map.Entry<String, String[]> entry : parameters.entrySet())
    {
      addParameters(entry.getKey(), entry.getValue());
    }
  }

public void addParameters ( Map < String , String [ ] > parameters ) { for ( Map . Entry < String , String [ ] > entry : parameters . entrySet ( ) ) { addParameters ( entry . getKey ( ) , entry . getValue ( ) ) ; } }

Adds the map of parameters
@param parameters


public void addIndexedParameter(String name, int value, int index)
  {
    addParameter(getIndexedParamName(name, index), value);
  }

public void addIndexedParameter ( String name , int value , int index ) { addParameter ( getIndexedParamName ( name , index ) , value ) ; }

Adds a parameter that comes from an array at the provided index

@param name the name of the parameter
@param value the value
@param index the index in the array


public void addQuery(URI uri)
  {
    try
    {
      addQuery(uri.getRawQuery(), false);
    }
    catch(URISyntaxException e)
    {
      // should not happen!
      throw new RuntimeException(e);
    }
  }

public
void
addQuery
(
URI
uri
)
{
try
{
addQuery
(
uri
.
getRawQuery
(
)
,
false
)
;
}
catch
(
URISyntaxException
e
)
{
// should not happen!
throw
new
RuntimeException
(
e
)
;
}
}

Adds the query extracted from the URI. No Exception is thrown because the
uri could not be built if it was not correct.

@param uri

Adds the query extracted from the URI . No Exception is thrown because the uri could not be built if it was not correct .


private void validateQuery(String query) throws URISyntaxException
  {
    if(query.length() == 0)
      return;

    Iterator<String> iter = SS.splitToIterator(query);

    while(iter.hasNext())
    {
      String s = iter.next();
      if(s.length() > 0)
      {
        int idx = s.indexOf('=');
        if(idx == -1)
          throw new URISyntaxException(query, "missing equal sign in " + s);
        if(s.lastIndexOf('=') != idx)
          throw new URISyntaxException(query, "extra equal sign in " + s);
      }
    }
  }

private
void
validateQuery
(
String
query
)
throws
URISyntaxException
{
if
(
query
.
length
(
)
==
0
)
return
;
Iterator
<
String
>
iter
=
SS
.
splitToIterator
(
query
)
;
while
(
iter
.
hasNext
(
)
)
{
String
s
=
iter
.
next
(
)
;
if
(
s
.
length
(
)
>
0
)
{
int
idx
=
s
.
indexOf
(
'
'
)
;
if
(
idx
==
1
)
throw
new
URISyntaxException
(
query
,
"missing equal sign in "
+
s
)
;
if
(
s
.
lastIndexOf
(
'
'
)
!=
idx
)
throw
new
URISyntaxException
(
query
,
"extra equal sign in "
+
s
)
;
}
}
}

Internal method in charge of validating the query provided. Exception
when query is not valid.

@param query the query to validate
@throws URISyntaxException if query invalid

Internal method in charge of validating the query provided . Exception when query is not valid .


public void addQuery(Query query)
  {
    if(query == null)
      return;
    try
    {
      if(!query.getEncoding().equals(getEncoding()))
        throw new RuntimeException("TODO");

      addQuery(query.getQuery(), false);
    }
    catch(URISyntaxException e)
    {
      // shouldn't happen since a query is already properly formatted
      throw new RuntimeException(e);
    }
  }

Simply adds the query provided.

@param query the query (null is ok)


private void rebuildQuery()
  {
    Map<String, String[]> map = getMap();

    // reset query instance and re-populate it again
    _query.setLength(0);
    for (String key : map.keySet())
    {
      String[] parameters = map.get(key);
      for (String param : parameters)
      {
        addQueryParameter(key, param);
      }
    }
  }

Rebuild query instance with values in the map.

Rebuild query instance with values in the map .


public String[] replaceParameter(String name, String value)
  {
    Map<String, String[]> map = getMap();
    String[] v = map.put(name, new String[] { value });
    rebuildQuery();
    return v;
  }

public String [ ] replaceParameter ( String name , String value ) { Map < String , String [ ] > map = getMap ( ) ; String [ ] v = map . put ( name , new String [ ] { value } ) ; rebuildQuery ( ) ; return v ; }

Replace existing or add new parameter with given
value. Any existing parameter values are
deleted prior to adding the new value.

@param name parameter to replace
@return previous values or null if parameter doesn't exist

Replace existing or add new parameter with given value . Any existing parameter values are deleted prior to adding the new value .


@Override
  public Object invoke(Object o, Method method, Object[] objects)
    throws Throwable
  {
    // throws ShutdownRequestedException when in shutdown mode
    _shutdown.startCall();
    try
    {
      return method.invoke(_object, objects);
    }
    catch(InvocationTargetException e)
    {
      Throwable th = e.getTargetException();

      try
      {
        throw th;
      }
      catch(Exception ex)
      {
        throw ex;
      }
      catch(Throwable throwable)
      {
        log.error(method.toString(), throwable);
        throw throwable;
      }
    }
    finally
    {
      _shutdown.endCall();
    }
  }

Method from the interface. Checks for shutdown then dispatches the call

@param o
@param method
@param objects
@return object
@throws Throwable

Method from the interface . Checks for shutdown then dispatches the call


public static Object createShutdownProxy(Object o,
                                           Class[] interfaces,
                                           Shutdown shutdown)
  {
    if(interfaces == null)
      interfaces = ReflectUtils.extractAllInterfaces(o);

    return Proxy.newProxyInstance(o.getClass().getClassLoader(),
                                  interfaces,
                                  new ShutdownProxy(o, shutdown));

  }

public static Object createShutdownProxy ( Object o , Class [ ] interfaces , Shutdown shutdown ) { if ( interfaces == null ) interfaces = ReflectUtils . extractAllInterfaces ( o ) ; return Proxy . newProxyInstance ( o . getClass ( ) . getClassLoader ( ) , interfaces , new ShutdownProxy ( o , shutdown ) ) ; }

Creates the proxy to check for shutdown.

@param o
@param interfaces restriction on which interface to apply the proxy on
@param shutdown
@return the proxy

Creates the proxy to check for shutdown .


public static boolean convertToBoolean(Object o)
  {
    if(o == null)
      return false;

    if(o instanceof Boolean)
    {
      return (Boolean) o;
    }

    return convertToBoolean(o.toString());
  }

public static boolean convertToBoolean ( Object o ) { if ( o == null ) return false ; if ( o instanceof Boolean ) { return ( Boolean ) o ; } return convertToBoolean ( o . toString ( ) ) ; }

Converts the object into a boolean value.

@param o the object to convert
@return a boolean

Converts the object into a boolean value .


public static String getStackTrace(Throwable th)
  {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    th.printStackTrace(pw);
    return sw.toString();
  }

public static String getStackTrace ( Throwable th ) { StringWriter sw = new StringWriter ( ) ; PrintWriter pw = new PrintWriter ( sw ) ; th . printStackTrace ( pw ) ; return sw . toString ( ) ; }

Returns the stack trace of the throwable as a string

@param th the throwable
@return the stack trace as a string


public static String removeTrailingSlash(String path)
  {
    if(path.endsWith("/"))
      return path.substring(0, path.length() - 1);
    else
      return path;
  }

public static String removeTrailingSlash ( String path ) { if ( path . endsWith ( "/" ) ) return path . substring ( 0 , path . length ( ) - 1 ) ; else return path ; }

Removes a trailing slash if exists

@param path
@return the path without a trailing /


@Override
  public void waitForShutdown(Object timeout)
    throws InterruptedException, IllegalStateException, TimeoutException
  {
    if(!_shutdown) throw new IllegalStateException("call shutdown first");
    pendingCallsCount.waitForCounter(timeout);
  }

@
Override
public
void
waitForShutdown
(
Object
timeout
)
throws
InterruptedException
,
IllegalStateException
,
TimeoutException
{
if
(
!
_shutdown
)
throw
new
IllegalStateException
(
"call shutdown first"
)
;
pendingCallsCount
.
waitForCounter
(
timeout
)
;
}

Waits for shutdown to be completed. After calling shutdown, there may still be some pending work
that needs to be accomplised. This method will block until it is done but no longer than the
timeout.

@param timeout how long to wait maximum for the shutdown
@throws InterruptedException  if interrupted while waiting
@throws IllegalStateException if shutdown has not been called
@throws TimeoutException      if shutdown still not complete after timeout

Waits for shutdown to be completed . After calling shutdown there may still be some pending work that needs to be accomplised . This method will block until it is done but no longer than the timeout .


@Override
  public void addEmptyTag(String tagName, Map attributes)
  {
    _xml.append('<').append(tagName);
    addAttributes(attributes);
    _xml.append(" />");
  }

@
Override
public
void
addEmptyTag
(
String
tagName
,
Map
attributes
)
{
_xml
.
append
(
'
'
)
.
append
(
tagName
)
;
addAttributes
(
attributes
)
;
_xml
.
append
(
" />"
)
;
}

Adds an empty tag which contains the attributes specified. All the
properties will be turned into attributes.

@param tagName the name of the empty tag to add
@param attributes the attributes

Adds an empty tag which contains the attributes specified . All the properties will be turned into attributes .


private void addAttribute(String attrName, String attrValue)
  {
    if(attrName == null)
      return;

    _xml.append(' ');
    _xml.append(attrName).append("=\"");
    _xml.append(XMLUtils.xmlEncode(attrValue)).append('"');
  }

private void addAttribute ( String attrName , String attrValue ) { if ( attrName == null ) return ; _xml . append ( ' ' ) ; _xml . append ( attrName ) . append ( "=\"" ) ; _xml . append ( XMLUtils . xmlEncode ( attrValue ) ) . append ( ' ' ) ; }

Adds the attribute

@param attrName name of the attribute to add
@param attrValue value of the attribute to add


private void addAttributes(Map attributes)
  {
    if(attributes == null)
      return;

    Iterator iter = attributes.keySet().iterator();
    while(iter.hasNext())
    {
      String attrName = (String) iter.next();
      Object attrValue = attributes.get(attrName);
      if(attrValue != null)
        addAttribute(attrName, attrValue.toString());
    }
  }

private void addAttributes ( Map attributes ) { if ( attributes == null ) return ; Iterator iter = attributes . keySet ( ) . iterator ( ) ; while ( iter . hasNext ( ) ) { String attrName = ( String ) iter . next ( ) ; Object attrValue = attributes . get ( attrName ) ; if ( attrValue != null ) addAttribute ( attrName , attrValue . toString ( ) ) ; } }

Adds the attributes. All the properties will be used as attributes

@param attributes the attributes to add

Adds the attributes . All the properties will be used as attributes


public static ResourceInfo extractInfo(URL url) throws IOException
  {
    URLConnection urlConnection = url.openConnection();

    urlConnection.setDoInput(true);
    urlConnection.setDoOutput(false);
    urlConnection.setUseCaches(false);
    urlConnection.connect();
    InputStream is = urlConnection.getInputStream();
    try
    {
      return new StaticInfo(urlConnection.getContentLength(), urlConnection.getLastModified());
    }
    finally
    {
      is.close();
    }
  }

public static ResourceInfo extractInfo ( URL url ) throws IOException { URLConnection urlConnection = url . openConnection ( ) ; urlConnection . setDoInput ( true ) ; urlConnection . setDoOutput ( false ) ; urlConnection . setUseCaches ( false ) ; urlConnection . connect ( ) ; InputStream is = urlConnection . getInputStream ( ) ; try { return new StaticInfo ( urlConnection . getContentLength ( ) , urlConnection . getLastModified ( ) ) ; } finally { is . close ( ) ; } }


@Override
  public InternalResource chroot(InternalResource resource)
  {
    String path = resource.getPath();

    // when it is a directory, we simply use the provided resource
    if(resource.isDirectory())
    {
      return doCreateResourceProvider(path).getRootResource();
    }
    else
    {
      // when not a directory, we do a chroot to the parent and then we return the resource
      // that points to it
      return (InternalResource) resource.chroot("..").createRelative(resource.getFilename());
    }
  }

Returns a new resource with the root resource set to this resource.

@return the new resource

Returns a new resource with the root resource set to this resource .


@Override
  public InternalResource[] list(InternalResource resource, final ResourceFilter filter)
    throws IOException
  {
    final List<Resource> resources = new ArrayList<Resource>();

    String path = PathUtils.addTrailingSlash(resource.getPath());

    if(doList(path, new ResourceFilter()
    {
      @Override
      public boolean accept(Resource resource)
      {
        boolean res = filter.accept(resource);
        if(res)
          resources.add(resource);
        return res;
      }
    }))
    {
      return resources.toArray(new InternalResource[resources.size()]);
    }
    else
      return null;
  }

@ Override public InternalResource [ ] list ( InternalResource resource , final ResourceFilter filter ) throws IOException { final List < Resource > resources = new ArrayList < Resource > ( ) ; String path = PathUtils . addTrailingSlash ( resource . getPath ( ) ) ; if ( doList ( path , new ResourceFilter ( ) { @ Override public boolean accept ( Resource resource ) { boolean res = filter . accept ( resource ) ; if ( res ) resources . add ( resource ) ; return res ; } } ) ) { return resources . toArray ( new InternalResource [ resources . size ( ) ] ) ; } else return null ; }

If this resource denotes a directory, then it will return all resources that are contained in
the directory.

@param filter the filter to include only some resources in the result
@return all the resources contained in the directory or null if not a directory
@throws IOException if there is an error accessing the resource

If this resource denotes a directory then it will return all resources that are contained in the directory .


@Override
  public Resource chroot(String relativePath)
  {
    return _resourceProvider.chroot((InternalResource) createRelative(relativePath));
  }

@ Override public Resource chroot ( String relativePath ) { return _resourceProvider . chroot ( ( InternalResource ) createRelative ( relativePath ) ) ; }

Returns a new resource with the root resource set to the relative path provided. Note that the
new resource points at the new root as well.

@param relativePath
@return the new resource

Returns a new resource with the root resource set to the relative path provided . Note that the new resource points at the new root as well .


public static Resource create(File file)
  {
    try
    {
      String path = file.getCanonicalPath();
      if(file.isDirectory())
        path = PathUtils.addTrailingSlash(path);
      return create(new File("/"), path);
    }
    catch(IOException e)
    {
      throw new IllegalArgumentException("invalid file " + file, e);
    }
  }

public
static
Resource
create
(
File
file
)
{
try
{
String
path
=
file
.
getCanonicalPath
(
)
;
if
(
file
.
isDirectory
(
)
)
path
=
PathUtils
.
addTrailingSlash
(
path
)
;
return
create
(
new
File
(
"/"
)
,
path
)
;
}
catch
(
IOException
e
)
{
throw
new
IllegalArgumentException
(
"invalid file "
+
file
,
e
)
;
}
}

Creates a file resource from a file

@param file the file
@return the resource (points to this file)


public void start() throws IOException
  {
    _process = _processBuilder.start();
    _out = new InputReader(new BufferedInputStream(_process.getInputStream()));
    _err = new InputReader(new BufferedInputStream(_process.getErrorStream()));

    _out.start();
    _err.start();
  }

public void start ( ) throws IOException { _process = _processBuilder . start ( ) ; _out = new InputReader ( new BufferedInputStream ( _process . getInputStream ( ) ) ) ; _err = new InputReader ( new BufferedInputStream ( _process . getErrorStream ( ) ) ) ; _out . start ( ) ; _err . start ( ) ; }

After creating the command, you have to start it...

@throws IOException

After creating the command you have to start it ...


public static ExternalCommand create(List<String> commands)
  {
    ExternalCommand ec = new ExternalCommand(new ProcessBuilder(commands));
    return ec;
  }

public static ExternalCommand create ( List < String > commands ) { ExternalCommand ec = new ExternalCommand ( new ProcessBuilder ( commands ) ) ; return ec ; }

Creates an external process from the command. It is not started and you have to call
start on it!

@param commands the command to execute
@return the process

Creates an external process from the command . It is not started and you have to call start on it!


public static ExternalCommand start(String... commands) throws IOException
  {
    ExternalCommand ec = new ExternalCommand(new ProcessBuilder(commands));
    ec.start();
    return ec;
  }

public static ExternalCommand start ( String ... commands ) throws IOException { ExternalCommand ec = new ExternalCommand ( new ProcessBuilder ( commands ) ) ; ec . start ( ) ; return ec ; }

Creates an external process from the command. The command is executed.

@param commands the commands to execute
@return the process
@throws IOException if there is an error

Creates an external process from the command . The command is executed .


public static ExternalCommand execute(File workingDirectory,
                                        String command,
                                        String... args)
      throws IOException, InterruptedException
  {
    try
    {
      return executeWithTimeout(workingDirectory, command, 0, args);
    }
    catch (TimeoutException e)
    {
      // Can't happen!
      throw new IllegalStateException(MODULE + ".execute: Unexpected timeout occurred!");
    }
  }

Executes the external command in the given working directory and waits for it to be
finished.

@param workingDirectory the root directory from where to run the command
@param command the command to execute (should be relative to the working directory
@param args the arguments to the command
@return the process

Executes the external command in the given working directory and waits for it to be finished .


public long tick()
  {
    long tick = _clock.currentTimeMillis();
    long diff = tick - _tick;

    _tick = tick;

    return diff;
  }

public long tick ( ) { long tick = _clock . currentTimeMillis ( ) ; long diff = tick - _tick ; _tick = tick ; return diff ; }

Returns the number of milliseconds ellapsed since the last call to
this function.

@return the number of milliseconds since last call

Returns the number of milliseconds ellapsed since the last call to this function .


public String getElapsedTime()
  {
    StringBuilder sb = new StringBuilder("Time: ");
    sb.append(this.tick());
    sb.append(" ms");

    return sb.toString();
  }

public
String
getElapsedTime
(
)
{
StringBuilder
sb
=
new
StringBuilder
(
"Time: "
)
;
sb
.
append
(
this
.
tick
(
)
)
;
sb
.
append
(
" ms"
)
;
return
sb
.
toString
(
)
;
}

Returns a string that represents the time elapsed

@return the elapsed time as a string


@Override
  public void addTag(String tagName,
                     int value,
                     String attrName,
                     String attrValue)
  {
    addTag(tagName, String.valueOf(value), attrName, attrValue);
  }

@ Override public void addTag ( String tagName , int value , String attrName , String attrValue ) { addTag ( tagName , String . valueOf ( value ) , attrName , attrValue ) ; }

Adds a tag which contains an attribute

@param tagName the name of the tag to add
@param value the value of the tag to add
@param attrName the name of the attribute
@param attrValue the value of the attribute


@Override
  public void addTag(String tagName, int value, Map attributes)
  {
    addTag(tagName, String.valueOf(value), attributes);
  }

@ Override public void addTag ( String tagName , int value , Map attributes ) { addTag ( tagName , String . valueOf ( value ) , attributes ) ; }

Adds a tag which contains the attributes specified. All the
properties will be turned into attributes.

@param tagName the name of the tag to add
@param value the value of the tag to add
@param attributes the attributes

Adds a tag which contains the attributes specified . All the properties will be turned into attributes .


public static String indentBlock(String block, Indent indent)
  {
    StringBuilder sb = new StringBuilder();

    BufferedReader br = new BufferedReader(new StringReader(block));
    String line;
    try
    {
      while((line = br.readLine()) != null)
        sb.append(indent).append(line).append('\n');
    }
    catch(IOException ex)
    {
      // on a String ? I doubt...
    }

    return sb.toString();
  }

public
static
String
indentBlock
(
String
block
,
Indent
indent
)
{
StringBuilder
sb
=
new
StringBuilder
(
)
;
BufferedReader
br
=
new
BufferedReader
(
new
StringReader
(
block
)
)
;
String
line
;
try
{
while
(
(
line
=
br
.
readLine
(
)
)
!=
)
sb
.
append
(
indent
)
.
append
(
line
)
.
append
(
'
'
)
;
}
catch
(
IOException
ex
)
{
// on a String ? I doubt...
}
return
sb
.
toString
(
)
;
}

Indents a block of text. You provide the block of text as a String and
the indent object and it returns another String with each line
properly indented.

@param block the block of text to indent
@param indent the indentation object to use
@return the indented block

Indents a block of text . You provide the block of text as a String and the indent object and it returns another String with each line properly indented .


public static long toEndTime(Clock clock, Object timeout)
  {
    Timespan t = toTimespan(timeout);
    if(t == null)
      return 0;
    if(clock == null)
      clock = SystemClock.INSTANCE;

    if(t.getDurationInMilliseconds() == 0)
      return 0;

    return t.futureTimeMillis(clock);
  }

public static long toEndTime ( Clock clock , Object timeout ) { Timespan t = toTimespan ( timeout ) ; if ( t == null ) return 0 ; if ( clock == null ) clock = SystemClock . INSTANCE ; if ( t . getDurationInMilliseconds ( ) == 0 ) return 0 ; return t . futureTimeMillis ( clock ) ; }

Computes the end time = now + timeout

@param clock can be null to use system clock
@param timeout (see {@link #toTimespan(Object)})
@return 0 if


public RAMEntry add(RAMEntry entry)
  {
    touch();
    _directoryContent.put(entry.name(), entry);
    return entry;
  }

public RAMEntry add ( RAMEntry entry ) { touch ( ) ; _directoryContent . put ( entry . name ( ) , entry ) ; return entry ; }

Copy the entry in this directory with the provided name

@param entry
@return the touched entry


public RAMDirectory mkdir(String name) throws IOException
  {
    RAMEntry entry = getEntry(name);
    if(entry instanceof RAMDirectory)
    {
      RAMDirectory ramDirectory = (RAMDirectory) entry;
      return ramDirectory;
    }
    else
    {
      if(entry == null)
      {
        RAMDirectory directory = new RAMDirectory(_clock, name);
        return (RAMDirectory) add(directory);
      }
      else
      {
        throw new IOException("File exists: " + name);
      }
    }
  }

public
RAMDirectory
mkdir
(
String
name
)
throws
IOException
{
RAMEntry
entry
=
getEntry
(
name
)
;
if
(
entry
instanceof
RAMDirectory
)
{
RAMDirectory
ramDirectory
=
(
RAMDirectory
)
entry
;
return
ramDirectory
;
}
else
{
if
(
entry
==
)
{
RAMDirectory
directory
=
new
RAMDirectory
(
_clock
,
name
)
;
return
(
RAMDirectory
)
add
(
directory
)
;
}
else
{
throw
new
IOException
(
"File exists: "
+
name
)
;
}
}
}

Creates an empty directory and add it to this directory with this name. If the directory
already exists, it does not recreate it.

@param name
@return the created directory
@throws IOException if the name represents a file

Creates an empty directory and add it to this directory with this name . If the directory already exists it does not recreate it .


public static String encodeString(OneWayCodec codec, String s)
  {
    try
    {
      return codec.encode(s.getBytes("UTF-8"));
    }
    catch(UnsupportedEncodingException ex)
    {
      // shouldn't happen
      throw new RuntimeException(ex);
    }
  }

public
static
String
encodeString
(
OneWayCodec
codec
,
String
s
)
{
try
{
return
codec
.
encode
(
s
.
getBytes
(
"UTF-8"
)
)
;
}
catch
(
UnsupportedEncodingException
ex
)
{
// shouldn't happen
throw
new
RuntimeException
(
ex
)
;
}
}

Encodes the string using the codec provided.

@param codec encode the string
@param s the string to encode
@return the encoded string

Encodes the string using the codec provided .


public static String decodeString(Codec codec, String s)
    throws Codec.CannotDecodeException
  {
    try
    {
      return new String(codec.decode(s), "UTF-8");
    }
    catch(UnsupportedEncodingException ex)
    {
      // shouldn't happen
      throw new RuntimeException(ex);
    }
  }

public
static
String
decodeString
(
Codec
codec
,
String
s
)
throws
Codec
.
CannotDecodeException
{
try
{
return
new
String
(
codec
.
decode
(
s
)
,
"UTF-8"
)
;
}
catch
(
UnsupportedEncodingException
ex
)
{
// shouldn't happen
throw
new
RuntimeException
(
ex
)
;
}
}

Decodes the string using the codec provided. Returns a string

@param codec encode the string
@param s the string to encode
@return the encoded string
@throws Codec.CannotDecodeException if cannot decode the string

Decodes the string using the codec provided . Returns a string


public static LeafResource create(Resource resource)
  {
    try
    {
      // if we can access the file then there is no reason to decorate it...
      resource.getFile();
      return new LeafResourceImpl(resource);
    }
    catch(IOException e)
    {
      return new LocalCacheLeafResource(resource);
    }
  }

Decorates the resource to implement a caching strategy.

@param resource the resource to cache locally
@return the (locally cached) resource

Decorates the resource to implement a caching strategy .


public static <T> T[] reverse(T[] array)
  {
    if(array == null)
      return array;

    int s = 0;
    int e = array.length - 1;
    while(s < e)
    {
      // swap index e and s
      T tmp = array[e];
      array[e] = array[s];
      array[s] = tmp;

      s++;
      e--;
    }

    return array;
  }

public
static
<
T
>
T
[
]
reverse
(
T
[
]
array
)
{
if
(
array
==
)
return
array
;
int
s
=
0
;
int
e
=
array
.
length
1
;
while
(
s
<
e
)
{
// swap index e and s
T
tmp
=
array
[
e
]
;
array
[
e
]
=
array
[
s
]
;
array
[
s
]
=
tmp
;
s
++
;
e
;
}
return
array
;
}

Reverses the array in place.
@param array the array to reverse
@return the same array provided NOT a new one!


public static <T extends Enum<T>> EnumSet<T> toEnumSet(Class<T> clazz, T... ts)
  {
    if(ts == null)
      return null;

    EnumSet<T> res = EnumSet.noneOf(clazz);
    for(T t : ts)
    {
      res.add(t);
    }
    return res;
  }

public static < T extends Enum < T > > EnumSet < T > toEnumSet ( Class < T > clazz , T ... ts ) { if ( ts == null ) return null ; EnumSet < T > res = EnumSet . noneOf ( clazz ) ; for ( T t : ts ) { res . add ( t ) ; } return res ; }

Turns an array of enumeration values into an enum set

@param clazz the type of the enum
@param ts the array of enums
@return the enum set containing all the values from the array


public static Properties loadProperties(File file) throws IOException
  {
    if(file == null)
      return null;

    FileReader reader = new FileReader(file);
    try
    {
      return loadProperties(reader);
    }
    finally
    {
      reader.close();
    }
  }

public static Properties loadProperties ( File file ) throws IOException { if ( file == null ) return null ; FileReader reader = new FileReader ( file ) ; try { return loadProperties ( reader ) ; } finally { reader . close ( ) ; } }

Convenient call to load a properties file from the provided file


public static Properties loadProperties(Reader reader) throws IOException
  {
    if(reader == null)
      return null;

    Properties properties = new Properties();
    properties.load(reader);
    return properties;
  }

public static Properties loadProperties ( Reader reader ) throws IOException { if ( reader == null ) return null ; Properties properties = new Properties ( ) ; properties . load ( reader ) ; return properties ; }

Convenient call to load a properties file from the provided reader


public String getAsString(EnumSet<TimeUnit> timeUnits)
  {
    StringBuilder sb = new StringBuilder();

    EnumMap<TimeUnit, Timespan> canonicalTimespans = getAsTimespans(timeUnits);
    for(TimeUnit timeUnit : TIME_UNIT_ORDER)
    {
      if(canonicalTimespans.containsKey(timeUnit))
      {
        long duration = canonicalTimespans.get(timeUnit).getDuration();
        if(duration > 0)
        {
          sb.append(duration).append(timeUnit.getDisplayChar());
        }
      }
    }

    if(sb.length() == 0)
    {
      sb.append(0);
      if(timeUnits.contains(getTimeUnit()))
        sb.append(getTimeUnit().getDisplayChar());
    }

    return sb.toString();
  }

public String getAsString ( EnumSet < TimeUnit > timeUnits ) { StringBuilder sb = new StringBuilder ( ) ; EnumMap < TimeUnit , Timespan > canonicalTimespans = getAsTimespans ( timeUnits ) ; for ( TimeUnit timeUnit : TIME_UNIT_ORDER ) { if ( canonicalTimespans . containsKey ( timeUnit ) ) { long duration = canonicalTimespans . get ( timeUnit ) . getDuration ( ) ; if ( duration > 0 ) { sb . append ( duration ) . append ( timeUnit . getDisplayChar ( ) ) ; } } } if ( sb . length ( ) == 0 ) { sb . append ( 0 ) ; if ( timeUnits . contains ( getTimeUnit ( ) ) ) sb . append ( getTimeUnit ( ) . getDisplayChar ( ) ) ; } return sb . toString ( ) ; }

Returns a string representing this timespan expressed with the units provided.

@param timeUnits the timeunits you want in the decomposition
@return a string representation using the units.
@see #getAsTimespans(EnumSet)

Returns a string representing this timespan expressed with the units provided .