Back to index

d-push  2.0
Public Member Functions | Static Public Member Functions | Public Attributes | Private Member Functions | Private Attributes
SyncCollections Class Reference

List of all members.

Public Member Functions

 SyncCollections ()
 Constructor.
 SetStateManager ($statemanager)
 Sets the StateManager for this object If this is not done and a method needs it, the StateManager will be requested from the DeviceManager.
 LoadAllCollections ($overwriteLoaded=false, $loadState=false, $checkPermissions=false)
 Loads all collections known for the current device.
 LoadCollection ($folderid, $loadState=false, $checkPermissions=false)
 Loads all collections known for the current device.
 SaveCollection ($spa)
 Saves a SyncParameters Object.
 AddCollection ($spa)
 Adds a SyncParameters object to the current list of collections.
 GetCollection ($folderid)
 Returns a previousily added or loaded SyncParameters object for a folderid.
 HasCollections ()
 Indicates if there are any loaded CPOs.
 AddParameter ($spa, $key, $value)
 Add a non-permanent key/value pair for a SyncParameters object.
 GetParameter ($spa, $key)
 Returns a previousily set non-permanent value for a SyncParameters object.
 GetReferencePolicyKey ()
 Returns the latest known PolicyKey to be used as reference.
 SetGlobalWindowSize ($windowsize)
 Sets a global window size which should be used for all collections in a case of a heartbeat and/or partial sync.
 GetGlobalWindowSize ()
 Returns the global window size which should be used for all collections in a case of a heartbeat and/or partial sync.
 SetLifetime ($lifetime)
 Sets the lifetime for heartbeat or ping connections.
 GetLifetime ()
 Sets the lifetime for heartbeat or ping connections previousily set or saved in a collection.
 GetLastSyncTime ()
 Returns the timestamp of the last synchronization for all loaded collections.
 CheckForChanges ($lifetime=600, $interval=30, $onlyPingable=false)
 Checks if the currently known collections for changes for $lifetime seconds.
 CountChanges ($onlyPingable=false)
 Checks if the currently known collections for changes performing Exporter->GetChangeCount()
 GetChangedFolderIds ()
 Returns an array with all folderid and the amount of changes found.
 WaitedForChanges ()
 Indicates if the process did wait in a sink, polling or before running a regular export to find changes.
 rewind ()
 Simple Iterator Interface implementation to traverse through collections.
 current ()
 Returns the current element.
 key ()
 Return the key of the current element.
 next ()
 Move forward to next element.
 valid ()
 Checks if current position is valid.

Static Public Member Functions

static GetLastSyncTimeOfDevice (&$device)
 Returns the timestamp of the last synchronization of a device.

Public Attributes

const ERROR_NO_COLLECTIONS = 1
const ERROR_WRONG_HIERARCHY = 2

Private Member Functions

 CountChange ($folderid)
 Checks a folder for changes performing Exporter->GetChangeCount()
 loadStateManager ()
 Gets the StateManager from the DeviceManager if it's not available.

Private Attributes

 $stateManager
 $collections = array()
 $addparms = array()
 $changes = array()
 $saveData = true
 $refPolicyKey = false
 $refLifetime = false
 $globalWindowSize
 $lastSyncTime
 $waitingTime = 0

Detailed Description

Definition at line 53 of file synccollections.php.


Member Function Documentation

Adds a SyncParameters object to the current list of collections.

Parameters:
SyncParameters$spapublic
Returns:
boolean

Definition at line 213 of file synccollections.php.

                                        {
        $this->collections[$spa->GetFolderId()] = $spa;

        if ($spa->HasLastSyncTime() && $spa->GetLastSyncTime() > $this->lastSyncTime) {
            $this->lastSyncTime = $spa->GetLastSyncTime();

            // use SyncParameters PolicyKey as reference if available
            if ($spa->HasReferencePolicyKey())
                $this->refPolicyKey = $spa->GetReferencePolicyKey();

            // use SyncParameters LifeTime as reference if available
            if ($spa->HasReferenceLifetime())
                $this->refLifetime = $spa->GetReferenceLifetime();
        }

        return true;
    }

Here is the caller graph for this function:

SyncCollections::AddParameter ( spa,
key,
value 
)

Add a non-permanent key/value pair for a SyncParameters object.

Parameters:
SyncParameters$spatarget SyncParameters
string$key
mixed$valuepublic
Returns:
boolean

Definition at line 266 of file synccollections.php.

                                                     {
        if (!$spa->HasFolderId())
            return false;

        $folderid = $spa->GetFolderId();
        if (!isset($this->addparms[$folderid]))
            $this->addparms[$folderid] = array();

        $this->addparms[$folderid][$key] = $value;
        return true;
    }
SyncCollections::CheckForChanges ( lifetime = 600,
interval = 30,
onlyPingable = false 
)

Checks if the currently known collections for changes for $lifetime seconds.

If the backend provides a ChangesSink the sink will be used. If not every $interval seconds an exporter will be configured for each folder to perform GetChangeCount().

Parameters:
int$lifetime(opt) total lifetime to wait for changes / default 600s
int$interval(opt) time between blocking operations of sink or polling / default 30s
boolean$onlyPingable(opt) only check for folders which have the PingableFlag

public

Returns:
boolean indicating if changes were found
Exceptions:
StatusExceptionwith code SyncCollections::ERROR_NO_COLLECTIONS if no collections available with code SyncCollections::ERROR_WRONG_HIERARCHY if there were errors getting changes

Definition at line 407 of file synccollections.php.

                                                                                            {
        $classes = array();
        foreach ($this->collections as $folderid => $spa){
            if ($onlyPingable && $spa->GetPingableFlag() !== true)
                continue;

            $classes[] = $spa->GetContentClass();
        }
        $checkClasses = implode("/", $classes);

        // is there something to check?
        if (empty($this->collections) || ($onlyPingable && empty($classes)))
            throw new StatusException("SyncCollections->CheckForChanges(): no collections available", self::ERROR_NO_COLLECTIONS);

        $pingTracking = new PingTracking();
        $this->changes = array();
        $changesAvailable = false;

        ZPush::GetTopCollector()->SetAsPushConnection();
        ZPush::GetTopCollector()->AnnounceInformation(sprintf("lifetime %ds", $lifetime), true);
        ZLog::Write(LOGLEVEL_INFO, sprintf("SyncCollections->CheckForChanges(): Waiting for changes... (lifetime %d seconds)", $lifetime));

        // use changes sink where available
        $changesSink = false;
        $forceRealExport = 0;
        if (ZPush::GetBackend()->HasChangesSink()) {
            $changesSink = true;

            // initialize all possible folders
            foreach ($this->collections as $folderid => $spa) {
                if ($onlyPingable && $spa->GetPingableFlag() !== true)
                    continue;

                // switch user store if this is a additional folder and initialize sink
                ZPush::GetBackend()->Setup(ZPush::GetAdditionalSyncFolderStore($folderid));
                if (! ZPush::GetBackend()->ChangesSinkInitialize($folderid))
                    throw new StatusException(sprintf("Error initializing ChangesSink for folder id '%s'", $folderid), self::ERROR_WRONG_HIERARCHY);
            }
        }

        // wait for changes
        $started = time();
        $endat = time() + $lifetime;
        while(($now = time()) < $endat) {
            // how long are we waiting for changes
            $this->waitingTime = $now-$started;

            $nextInterval = $interval;
            // we should not block longer than the lifetime
            if ($endat - $now < $nextInterval)
                $nextInterval = $endat - $now;

            // Check if provisioning is necessary
            // if a PolicyKey was sent use it. If not, compare with the ReferencePolicyKey
            if (PROVISIONING === true && $this->GetReferencePolicyKey() !== false && ZPush::GetDeviceManager()->ProvisioningRequired($this->GetReferencePolicyKey(), true))
                // the hierarchysync forces provisioning
                throw new StatusException("SyncCollections->CheckForChanges(): PolicyKey changed. Provisioning required.", self::ERROR_WRONG_HIERARCHY);

            // Check if a hierarchy sync is necessary
            if (ZPush::GetDeviceManager()->IsHierarchySyncRequired())
                throw new StatusException("SyncCollections->CheckForChanges(): HierarchySync required.", self::ERROR_WRONG_HIERARCHY);

            // Check if there are newer requests
            // If so, this process should be terminated if more than 60 secs to go
            if ($pingTracking->DoForcePingTimeout()) {
                // do not update CPOs because another process has already read them!
                $this->saveData = false;

                // more than 60 secs to go?
                if (($now + 60) < $endat) {
                    ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->CheckForChanges(): Timeout forced after %ss from %ss due to other process", ($now-$started), $lifetime));
                    ZPush::GetTopCollector()->AnnounceInformation(sprintf("Forced timeout after %ds", ($now-$started)), true);
                    return false;
                }
            }

            // Use changes sink if available
            if ($changesSink) {
                // in some occasions we do realize a full export to see if there are pending changes
                // every 5 minutes this is also done to see if there were "missed" notifications
                if (SINK_FORCERECHECK !== false && $forceRealExport+SINK_FORCERECHECK <= $now) {
                    if ($this->CountChanges($onlyPingable)) {
                        ZLog::Write(LOGLEVEL_DEBUG, "SyncCollections->CheckForChanges(): Using ChangesSink but found relevant changes on regular export");
                        return true;
                    }
                    $forceRealExport = $now;
                }

                ZPush::GetTopCollector()->AnnounceInformation(sprintf("Sink %d/%ds on %s", ($now-$started), $lifetime, $checkClasses));
                $notifications = ZPush::GetBackend()->ChangesSink($nextInterval);

                $validNotifications = false;
                foreach ($notifications as $folderid) {
                    // check if the notification on the folder is within our filter
                    if ($this->CountChange($folderid)) {
                        ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->CheckForChanges(): Notification received on folder '%s'", $folderid));
                        $validNotifications = true;
                    }
                    else {
                        ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->CheckForChanges(): Notification received on folder '%s', but it is not relevant", $folderid));
                    }
                }
                if ($validNotifications)
                    return true;
            }
            // use polling mechanism
            else {
                ZPush::GetTopCollector()->AnnounceInformation(sprintf("Polling %d/%ds on %s", ($now-$started), $lifetime, $checkClasses));
                if ($this->CountChanges($onlyPingable)) {
                    ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->CheckForChanges(): Found changes polling"));
                    return true;
                }
                else {
                    sleep($nextInterval);
                }
            } // end polling
        } // end wait for changes
        ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->CheckForChanges(): no changes found after %ds", time() - $started));

        return false;
    }

Here is the call graph for this function:

SyncCollections::CountChange ( folderid) [private]

Checks a folder for changes performing Exporter->GetChangeCount()

Parameters:
string$folderidcounts changes for a folder

private

Returns:
boolean indicating if changes were found or not

Definition at line 562 of file synccollections.php.

                                             {
        $spa = $this->GetCollection($folderid);

        // switch user store if this is a additional folder (additional true -> do not debug)
        ZPush::GetBackend()->Setup(ZPush::GetAdditionalSyncFolderStore($folderid, true));
        $changecount = false;

        try {
            $exporter = ZPush::GetBackend()->GetExporter($folderid);
            if ($exporter !== false && isset($this->addparms[$folderid]["state"])) {
                $importer = false;

                $exporter->Config($this->addparms[$folderid]["state"], BACKEND_DISCARD_DATA);
                $exporter->ConfigContentParameters($spa->GetCPO());
                $ret = $exporter->InitializeExporter($importer);

                if ($ret !== false)
                    $changecount = $exporter->GetChangeCount();
            }
        }
        catch (StatusException $ste) {
            throw new StatusException("SyncCollections->CountChange(): exporter can not be re-configured.", self::ERROR_WRONG_HIERARCHY, null, LOGLEVEL_WARN);
        }

        // start over if exporter can not be configured atm
        if ($changecount === false )
            ZLog::Write(LOGLEVEL_WARN, "SyncCollections->CountChange(): no changes received from Exporter.");

        $this->changes[$folderid] = $changecount;

        if(isset($this->addparms[$folderid]['savestate'])) {
            try {
                // Discard any data
                while(is_array($exporter->Synchronize()));
                $this->addparms[$folderid]['savestate'] = $exporter->GetState();
            }
            catch (StatusException $ste) {
                throw new StatusException("SyncCollections->CountChange(): could not get new state from exporter", self::ERROR_WRONG_HIERARCHY, null, LOGLEVEL_WARN);
            }
        }

        return ($changecount > 0);
     }

Here is the call graph for this function:

Here is the caller graph for this function:

SyncCollections::CountChanges ( onlyPingable = false)

Checks if the currently known collections for changes performing Exporter->GetChangeCount()

Parameters:
boolean$onlyPingable(opt) only check for folders which have the PingableFlag

public

Returns:
boolean indicating if changes were found or not

Definition at line 538 of file synccollections.php.

                                                        {
        $changesAvailable = false;
        foreach ($this->collections as $folderid => $spa) {
            if ($onlyPingable && $spa->GetPingableFlag() !== true)
                continue;

            if (isset($this->addparms[$spa->GetFolderId()]["status"]) && $this->addparms[$spa->GetFolderId()]["status"] != SYNC_STATUS_SUCCESS)
                continue;

            if ($this->CountChange($folderid))
                $changesAvailable = true;
        }

        return $changesAvailable;
    }

Here is the call graph for this function:

Here is the caller graph for this function:

Returns the current element.

public

Returns:
mixed

Definition at line 647 of file synccollections.php.

                              {
        return current($this->collections);
    }

Returns an array with all folderid and the amount of changes found.

public

Returns:
array

Definition at line 612 of file synccollections.php.

                                          {
        return $this->changes;
    }

Returns a previousily added or loaded SyncParameters object for a folderid.

Parameters:
SyncParameters$spapublic
Returns:
SyncParameters / boolean false if no SyncParameters object is found for folderid

Definition at line 239 of file synccollections.php.

                                             {
        if (isset($this->collections[$folderid]))
            return $this->collections[$folderid];
        else
            return false;
    }

Here is the caller graph for this function:

Returns the global window size which should be used for all collections in a case of a heartbeat and/or partial sync.

public

Returns:
int/boolean returns false if not set or not available

Definition at line 325 of file synccollections.php.

                                          {
        if (!isset($this->globalWindowSize))
            return false;

        return $this->globalWindowSize;
    }

Returns the timestamp of the last synchronization for all loaded collections.

public

Returns:
int timestamp

Definition at line 366 of file synccollections.php.

                                      {
        return $this->lastSyncTime;
    }
static SyncCollections::GetLastSyncTimeOfDevice ( &$  device) [static]

Returns the timestamp of the last synchronization of a device.

Parameters:
$devicean ASDevice

public

Returns:
int timestamp

Definition at line 378 of file synccollections.php.

                                                             {
        // we need a StateManager for this operation
        $stateManager = new StateManager();
        $stateManager->SetDevice($device);

        $sc = new SyncCollections();
        $sc->SetStateManager($stateManager);

        // load all collections of device without loading states or checking permissions
        $sc->LoadAllCollections(true, false, false);

        return $sc->GetLastSyncTime();
    }

Here is the call graph for this function:

Here is the caller graph for this function:

Sets the lifetime for heartbeat or ping connections previousily set or saved in a collection.

public

Returns:
int returns 600 as default if nothing set or not available

Definition at line 352 of file synccollections.php.

                                  {
        if (!isset( $this->refLifetime) || $this->refLifetime === false)
            return 600;

        return $this->refLifetime;
    }
SyncCollections::GetParameter ( spa,
key 
)

Returns a previousily set non-permanent value for a SyncParameters object.

Parameters:
SyncParameters$spatarget SyncParameters
string$keypublic
Returns:
mixed returns 'null' if nothing set

Definition at line 287 of file synccollections.php.

                                             {
        if (isset($this->addparms[$spa->GetFolderId()]) && isset($this->addparms[$spa->GetFolderId()][$key]))
            return $this->addparms[$spa->GetFolderId()][$key];
        else
            return null;
    }

Returns the latest known PolicyKey to be used as reference.

public

Returns:
int/boolen returns false if nothing found in collections

Definition at line 300 of file synccollections.php.

                                            {
        return $this->refPolicyKey;
    }

Here is the caller graph for this function:

Indicates if there are any loaded CPOs.

public

Returns:
boolean

Definition at line 252 of file synccollections.php.

                                     {
        return ! empty($this->collections);
    }

Return the key of the current element.

public

Returns:
scalar on success, or NULL on failure.

Definition at line 657 of file synccollections.php.

                          {
        return key($this->collections);
    }

Here is the caller graph for this function:

SyncCollections::LoadAllCollections ( overwriteLoaded = false,
loadState = false,
checkPermissions = false 
)

Loads all collections known for the current device.

Parameters:
boolean$overwriteLoaded(opt) overwrites Collection with saved state if set to true
boolean$loadState(opt) indicates if the collection sync state should be loaded, default true
boolean$checkPermissions(opt) if set to true each folder will pass through a backend->Setup() to check permissions. If this fails a StatusException will be thrown.

public

Exceptions:
StatusExceptionwith SyncCollections::ERROR_WRONG_HIERARCHY if permission check fails
StateNotFoundExceptionif the sync state can not be found ($loadState = true)
Returns:
boolean

Definition at line 107 of file synccollections.php.

                                                                                                                {
        $this->loadStateManager();

        $invalidStates = false;
        foreach($this->stateManager->GetSynchedFolders() as $folderid) {
            if ($overwriteLoaded === false && isset($this->collections[$folderid]))
                continue;

            // Load Collection!
            if (! $this->LoadCollection($folderid, $loadState, $checkPermissions))
                $invalidStates = true;
        }

        if ($invalidStates)
            throw new StateInvalidException("Invalid states found while loading collections. Forcing sync");

        return true;
    }

Here is the call graph for this function:

SyncCollections::LoadCollection ( folderid,
loadState = false,
checkPermissions = false 
)

Loads all collections known for the current device.

Parameters:
boolean$folderidfolder id to be loaded
boolean$loadState(opt) indicates if the collection sync state should be loaded, default true
boolean$checkPermissions(opt) if set to true each folder will pass through a backend->Setup() to check permissions. If this fails a StatusException will be thrown.

public

Exceptions:
StatusExceptionwith SyncCollections::ERROR_WRONG_HIERARCHY if permission check fails
StateNotFoundExceptionif the sync state can not be found ($loadState = true)
Returns:
boolean

Definition at line 140 of file synccollections.php.

                                                                                             {
        $this->loadStateManager();

        try {
            // Get SyncParameters for the folder from the state
            $spa = $this->stateManager->GetSynchedFolderState($folderid);

            // TODO remove resync of folders for < Z-Push 2 beta4 users
            // this forces a resync of all states previous to Z-Push 2 beta4
            if (! $spa instanceof SyncParameters)
                throw new StateInvalidException("Saved state are not of type SyncParameters");
        }
        catch (StateInvalidException $sive) {
            // in case there is something wrong with the state, just stop here
            // later when trying to retrieve the SyncParameters nothing will be found

            // we also generate a fake change, so a sync on this folder is triggered
            $this->changes[$folderid] = 1;

            return false;
        }

        // if this is an additional folder the backend has to be setup correctly
        if ($checkPermissions === true && ! ZPush::GetBackend()->Setup(ZPush::GetAdditionalSyncFolderStore($spa->GetFolderId())))
            throw new StatusException(sprintf("SyncCollections->LoadCollection(): could not Setup() the backend for folder id '%s'", $spa->GetFolderId()), self::ERROR_WRONG_HIERARCHY);

        // add collection to object
        $this->AddCollection($spa);

        // load the latest known syncstate if requested
        if ($loadState === true)
            $this->addparms[$folderid]["state"] = $this->stateManager->GetSyncState($spa->GetLatestSyncKey());

        return true;
    }

Here is the call graph for this function:

Here is the caller graph for this function:

Gets the StateManager from the DeviceManager if it's not available.

private

Returns:

Definition at line 688 of file synccollections.php.

                                         {
         if (!isset($this->stateManager))
            $this->stateManager = ZPush::GetDeviceManager()->GetStateManager();
     }

Here is the call graph for this function:

Here is the caller graph for this function:

Move forward to next element.

public

Returns:

Definition at line 667 of file synccollections.php.

                           {
        return next($this->collections);
    }

Simple Iterator Interface implementation to traverse through collections.

Rewind the Iterator to the first element

public

Returns:

Definition at line 637 of file synccollections.php.

                             {
        return reset($this->collections);
    }

Saves a SyncParameters Object.

Parameters:
SyncParamerts$spapublic
Returns:
boolean

Definition at line 184 of file synccollections.php.

                                         {
        if (! $this->saveData)
            return false;

        if ($spa->IsDataChanged()) {
            $this->loadStateManager();
            ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncCollections->SaveCollection(): Data of folder '%s' changed", $spa->GetFolderId()));

            // save new windowsize
            if (isset($this->globalWindowSize))
                $spa->SetWindowSize($this->globalWindowSize);

            // update latest lifetime
            if (isset($this->refLifetime))
                $spa->SetReferenceLifetime($this->refLifetime);

            return $this->stateManager->SetSynchedFolderState($spa);
        }
        return false;
    }

Here is the call graph for this function:

Sets a global window size which should be used for all collections in a case of a heartbeat and/or partial sync.

Parameters:
int$windowsizepublic
Returns:
boolean

Definition at line 313 of file synccollections.php.

                                                     {
        $this->globalWindowSize = $windowsize;
        return true;
    }

Sets the lifetime for heartbeat or ping connections.

Parameters:
int$lifetimetime in seconds

public

Returns:
boolean

Definition at line 340 of file synccollections.php.

                                           {
        $this->refLifetime = $lifetime;
        return true;
    }
SyncCollections::SetStateManager ( statemanager)

Sets the StateManager for this object If this is not done and a method needs it, the StateManager will be requested from the DeviceManager.

Parameters:
StateManager$statemanagerpublic
Returns:

Definition at line 89 of file synccollections.php.

                                                   {
        $this->stateManager = $statemanager;
    }

Constructor.

Definition at line 76 of file synccollections.php.

                                      {
    }

Here is the caller graph for this function:

Checks if current position is valid.

public

Returns:
boolean

Definition at line 677 of file synccollections.php.

                            {
        return (key($this->collections) !== null);
    }

Here is the call graph for this function:

Indicates if the process did wait in a sink, polling or before running a regular export to find changes.

public

Returns:
array

Definition at line 623 of file synccollections.php.

                                       {
        return ($this->waitingTime > 1);
    }

Member Data Documentation

SyncCollections::$addparms = array() [private]

Definition at line 60 of file synccollections.php.

SyncCollections::$changes = array() [private]

Definition at line 61 of file synccollections.php.

SyncCollections::$collections = array() [private]

Definition at line 59 of file synccollections.php.

Definition at line 67 of file synccollections.php.

Definition at line 68 of file synccollections.php.

SyncCollections::$refLifetime = false [private]

Definition at line 65 of file synccollections.php.

SyncCollections::$refPolicyKey = false [private]

Definition at line 64 of file synccollections.php.

SyncCollections::$saveData = true [private]

Definition at line 62 of file synccollections.php.

Definition at line 57 of file synccollections.php.

Definition at line 70 of file synccollections.php.

Definition at line 54 of file synccollections.php.

Definition at line 55 of file synccollections.php.


The documentation for this class was generated from the following file: