Logo Search packages:      
Sourcecode: gdata-sharp version File versions  Download package

service.cs

/* Copyright (c) 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
/* Change history
* Oct 13 2008  Joe Feser       joseph.feser@gmail.com
* Removed warnings
* 
*/
#region Using directives

#define USE_TRACING

using System;
using System.Xml;
using System.IO;
using System.Net;
using System.Threading;
using System.ComponentModel;
using System.Collections.Specialized;



#endregion

/////////////////////////////////////////////////////////////////////
// <summary>contains Service, the base interface that 
//   allows to query a service for different feeds
//  </summary>
////////////////////////////////////////////////////////////////////
namespace Google.GData.Client
{

    /// <summary>
    /// EventArgument class for service level events during parsing
    /// </summary>
00047     public class ServiceEventArgs : EventArgs
    {
        private AtomFeed feedObject;
        private IService service;
        private Uri uri;

        /// <summary>
        /// constructor. Takes the URI and the service this event applies to
        /// </summary>
        /// <param name="uri">URI currently executed</param>
        /// <param name="service">service object doing the execution</param>
00058         public ServiceEventArgs(Uri uri, IService service) 
        {
            this.service = service;
            this.uri = uri;
        }
    
        /// <summary>the feed to be created. If this is NULL, a service 
        /// will create a DEFAULT atomfeed</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AtomFeed Feed
00069         {
            get {return this.feedObject;}
            set {this.feedObject = value;}
        }
        ////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////
        /// <summary>the service to be used for the feed to be created. </summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public IService Service
00079         {
            get {return this.service;}
        }
        ////////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////
        /// <summary>the Uri to be used</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public Uri Uri
00088         {
            get {return this.uri;}
        }
        ////////////////////////////////////////////////////////////////////////
   }



    /// <summary>Delegate declaration for the feed creation in a service</summary> 
    public delegate void ServiceEventHandler(object sender, ServiceEventArgs e);


   
    //////////////////////////////////////////////////////////////////////
    /// <summary>base Service implementation
    /// </summary> 
    //////////////////////////////////////////////////////////////////////
    public partial class Service : IService, IVersionAware
    {
        /// <summary>holds the credential information</summary> 
00108         private GDataCredentials credentials; 
        /// <summary>the GDatarequest to use</summary> 
00110         private IGDataRequestFactory factory;
        /// <summary>holds the hooks for the eventing in the feedparser</summary> 
00112         public event FeedParserEventHandler NewAtomEntry;
        /// <summary>eventhandler, when the parser finds a new extension element-> mirrored from underlying parser</summary> 
00114         public event ExtensionElementEventHandler NewExtensionElement;
        /// <summary>eventhandler, when the service needs to create a new feed</summary> 
00116         public event ServiceEventHandler NewFeed;

        private string serviceID;


        //////////////////////////////////////////////////////////////////////
        /// <summary>default constructor, sets the default GDataRequest</summary> 
        //////////////////////////////////////////////////////////////////////
00124         public Service()
        {
            this.RequestFactory = new GDataRequestFactory(this.GetType().Name);
            InitDelegates();
            InitVersionInformation();
        }
        /////////////////////////////////////////////////////////////////////////////
 

        //////////////////////////////////////////////////////////////////////
        /// <summary>default constructor, sets the default GDataRequest</summary> 
        //////////////////////////////////////////////////////////////////////
00136         public Service(string applicationName)
        {
            this.RequestFactory = new GDataRequestFactory(applicationName == null ? 
                                                            this.GetType().Name : 
                                                            applicationName);
            InitDelegates();
            InitVersionInformation();
        }
        /////////////////////////////////////////////////////////////////////////////
 

        //////////////////////////////////////////////////////////////////////
        /// <summary>this will trigger the creation of an authenticating service</summary> 
        //////////////////////////////////////////////////////////////////////
00150         public Service(string service, string applicationName)
        {
            this.RequestFactory = new GDataGAuthRequestFactory(service, applicationName);
            this.serviceID = service; 
            InitDelegates();
            InitVersionInformation();
        }
        /////////////////////////////////////////////////////////////////////////////
 

        /// <summary>
        /// this returns the string that the services uses to identify the google service to use
        /// when authentication with Google is required. Examples are "cl" for calendar, e.g. 
        /// </summary>
        /// <returns></returns>
        public string ServiceIdentifier
00166         {
            get
            {
                return this.serviceID;
            }
        }
  
        private VersionInformation versionInfo = new VersionInformation();
        /// <summary>
        /// returns the major protocol version number this element 
        /// is working against. 
        /// </summary>
        /// <returns></returns>
        public int ProtocolMajor
00180         {
            get
            {
                return this.versionInfo.ProtocolMajor;
            }
            set
            {
                this.versionInfo.ProtocolMajor  = value;
                PropagateVersionInfo();
            }
        }

        /// <summary>
        /// returns the minor protocol version number this element 
        /// is working against. 
        /// </summary>
        /// <returns></returns>
        public int ProtocolMinor
00198         {
            get
            {
                return this.versionInfo.ProtocolMinor;
            }
            set
            {
                this.versionInfo.ProtocolMinor  = value;
                PropagateVersionInfo();
            }
        }
        
        /// <summary>
        /// by default all services now use version 2 for the protocol.
        /// this needs to be overridden by a service to specify otherwise. 
        /// </summary>
        /// <returns></returns>
00215         protected virtual void InitVersionInformation()
        {
        }

        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public IGDataRequest Request</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public IGDataRequestFactory RequestFactory
00224         {
            get { return this.factory; }
            set { this.factory = value; OnRequestFactoryChanged(); }
        }

        /// <summary>
        /// notifier if someone changes the requestfactory of the service. 
        /// This will cause the service to set the versionnumber on the 
        /// request factory to it's own
        /// </summary>
00234         public virtual void OnRequestFactoryChanged() 
        {
            PropagateVersionInfo();
        }

        private void PropagateVersionInfo()
        {
            IVersionAware v = this.factory as IVersionAware;
            if (v != null)
            {
                v.ProtocolMajor = this.ProtocolMajor;
                v.ProtocolMinor = this.ProtocolMinor;
            }
            return; 
        }

        //////////////////////////////////////////////////////////////////////
        /// <summary>accessor method public ICredentials Credentials</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public GDataCredentials Credentials
00255         {
            get {return this.credentials;}
            set 
            {
                this.credentials = value; 
                // if we get new credentials, make sure we invalidate the old authtoken
                SetAuthenticationToken(value == null ? null : value.ClientToken);
            }
        }
        /////////////////////////////////////////////////////////////////////////////


        /// <summary>
        /// if the service is using a Google Request Factory it will use that 
        /// assuming credentials are set to retrieve the authentication token
        /// for those credentials
        /// </summary>
        /// <returns>string</returns>
00273         public string QueryAuthenticationToken() 
        {
            if (this.Credentials != null)
            {
                GDataGAuthRequestFactory factory = this.factory as GDataGAuthRequestFactory;
                if (factory != null)
                {
                    return factory.QueryAuthToken(this.Credentials);
                }
            }
            return null;
        }

        /// <summary>
        /// if the service is using a Google Request Factory it will set the passed 
        /// in token to the factory. NET CF does not support authsubtokens here
        /// </summary>
        /// <returns>string</returns>
00291         public void SetAuthenticationToken(string token) 
        {
            GDataGAuthRequestFactory factory = this.factory as GDataGAuthRequestFactory;
            if (factory != null)
            {
                factory.GAuthToken = token;
            }
#if WindowsCE || PocketPC
#else
            else 
            {
                GAuthSubRequestFactory f = this.factory as GAuthSubRequestFactory;
                if (f != null)
                {
                    f.Token = token;
                }
            }
#endif
        }

        /// <summary>
        /// Sets the credentials of the user to authenticate requests
        /// to the server.
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
00317         public void setUserCredentials(String username, String password)
        {
            this.Credentials = new GDataCredentials(username, password);
        }



   
        //////////////////////////////////////////////////////////////////////
        /// <summary>the basic interface. Take a URI and just get it</summary> 
        /// <param name="queryUri">the URI to execute</param>
        /// <returns> a webresponse object</returns>
        //////////////////////////////////////////////////////////////////////
00330         public Stream Query(Uri queryUri)
        {
          return Query(queryUri, DateTime.MinValue);
        }

        //////////////////////////////////////////////////////////////////////
        /// <summary>the basic interface. Take a URI and just get it</summary> 
        /// <param name="queryUri">the URI to execute</param>
        /// <param name="ifModifiedSince">used to set a precondition date that 
        /// indicates the feed should be returned only if it has been modified 
        /// after the specified date. A value of DateTime.MinValue indicates no 
        /// precondition.</param>
        /// <returns> a webresponse object</returns>
        //////////////////////////////////////////////////////////////////////
00344         public Stream Query(Uri queryUri, DateTime ifModifiedSince)
        {
            long l;
            return this.Query(queryUri, ifModifiedSince, null, out l);
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>the basic interface. Take a URI and just get it</summary> 
        /// <param name="queryUri">the URI to execute</param>
        /// <param name="etag">used to set a precondition etag that 
        /// indicates the feed should be returned only if it has been modified </param>
        /// <returns> a webresponse object</returns>
        //////////////////////////////////////////////////////////////////////
00359         public Stream Query(Uri queryUri, string etag)
        {
            long l;
            return this.Query(queryUri, DateTime.MinValue, etag, out l);
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>the basic interface. Take a URI and just get it</summary> 
        /// <param name="queryUri">the URI to execute</param>
        /// <param name="ifModifiedSince">used to set a precondition date that 
        /// indicates the feed should be returned only if it has been modified 
        /// after the specified date. A value of DateTime.MinValue indicates no 
        /// precondition.</param>
        /// <param name="etag">used to set a precondition etag that 
        /// indicates the feed should be returned only if it has been modified </param>
        /// <param name="contentLength">returns the content length of the response</param>
        /// <returns> a webresponse object</returns>
        //////////////////////////////////////////////////////////////////////
00378         private Stream Query(Uri queryUri, DateTime ifModifiedSince, string etag, out long contentLength)
        {
            Tracing.TraceCall("Enter");
            if (queryUri == null)
            {
              throw new System.ArgumentNullException("queryUri");
            }

            contentLength = -1; 

            IGDataRequest request = this.RequestFactory.CreateRequest(GDataRequestType.Query, queryUri);
            request.Credentials = this.Credentials;
            request.IfModifiedSince = ifModifiedSince;

            if (etag != null)
            {
                ISupportsEtag ise = request as ISupportsEtag;
                if (ise != null)
                {
                    ise.Etag = etag; 
                }
            }

            try
            {
              request.Execute();
            }
            catch (Exception)
            {
              // Prevent connection leaks
              if (request.GetResponseStream() != null)
                request.GetResponseStream().Close();

              throw;
            }

            // return the response
            GDataGAuthRequest gr = request as GDataGAuthRequest;
            if (gr != null)
            {
                 contentLength = gr.ContentLength;
            }
            
            Tracing.TraceCall("Exit");
            return new GDataReturnStream(request);
        }
        /////////////////////////////////////////////////////////////////////////////


        /// <summary>
        /// Returns a single Atom entry based upon its unique URI.
        /// </summary>
        /// <param name="entryUri">The URI of the Atom entry.</param>
        /// <returns>AtomEntry representing the entry.</returns>
00432         public AtomEntry Get(string entryUri)
        {
            FeedQuery query = new FeedQuery(entryUri);
            AtomFeed resultFeed = Query(query);
            return resultFeed.Entries[0];
        }


   
        //////////////////////////////////////////////////////////////////////
        /// <summary>executes the query and returns an AtomFeed object tree</summary> 
        /// <param name="feedQuery">the query parameters as a FeedQuery object </param>
        /// <returns>AtomFeed object tree</returns>
        //////////////////////////////////////////////////////////////////////
00446         public AtomFeed Query(FeedQuery feedQuery)
        {
            AtomFeed feed = null;
            Tracing.TraceCall("Enter");

            if (feedQuery == null)
            {
                throw new System.ArgumentNullException("feedQuery", "The query argument MUST not be null");
            }
            // Create a new request to the Uri in the query object...    
            Uri targetUri = null;

            try
            {
                targetUri = feedQuery.Uri;

            }
            catch (System.UriFormatException)
            {
                throw new System.ArgumentException("The query argument MUST contain a valid Uri", "feedQuery");
            }

            Tracing.TraceInfo("Service:Query - about to query");

            Stream responseStream = null;

            if (feedQuery.Etag != null)
            {
                responseStream = Query(targetUri, feedQuery.Etag);
            }
            else
            {
                responseStream = Query(targetUri, feedQuery.ModifiedSince);
            }

            Tracing.TraceInfo("Service:Query - query done");
            if (responseStream != null)
            {
                feed = CreateAndParseFeed(responseStream, feedQuery.Uri);
            }
            Tracing.TraceCall("Exit");
            return feed;
 
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>executes the query and returns an AtomFeed object tree</summary> 
        /// <param name="feedQuery">the query parameters as a FeedQuery object </param>
        /// <param name="ifModifiedSince">used to set a precondition date that 
        /// indicates the feed should be returned only if it has been modified 
        /// after the specified date. A value of null indicates no 
        /// precondition.</param>
        /// <returns>AtomFeed object tree</returns>
        //////////////////////////////////////////////////////////////////////
        [Obsolete("FeedQuery has a modifiedSince property, use that instead")] 
00503         public AtomFeed Query(FeedQuery feedQuery, DateTime ifModifiedSince)
        {
            feedQuery.ModifiedSince = ifModifiedSince;
            return Query(feedQuery);
        }
        /////////////////////////////////////////////////////////////////////////////





        //////////////////////////////////////////////////////////////////////
        /// <summary>object QueryOpenSearchRssDescription()</summary> 
        /// <param name="serviceUri">the service to ask for an OpenSearchRss Description</param> 
        /// <returns> a webresponse object</returns>
        //////////////////////////////////////////////////////////////////////
00519         public Stream QueryOpenSearchRssDescription(Uri serviceUri)
        {
            if (serviceUri == null)
            {
                throw new System.ArgumentNullException("serviceUri");
            }
            IGDataRequest request = this.RequestFactory.CreateRequest(GDataRequestType.Query, serviceUri);
            request.Credentials = this.Credentials;
            request.Execute();
            // return the response
            return request.GetResponseStream();
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>WebResponse Update(Uri updateUri, Stream entryStream, ICredentials credentials)</summary> 
        /// <param name="entry">the old entry to update</param> 
        /// <returns> the new Entry, as returned from the server</returns>
        //////////////////////////////////////////////////////////////////////
00540         public AtomEntry Update(AtomEntry entry)
        {
            return this.Update(entry, null); 
        }
        /////////////////////////////////////////////////////////////////////////////




        //////////////////////////////////////////////////////////////////////
        /// <summary>templated type safe verion of the interface</summary> 
        /// <param name="entry">the old entry to update</param> 
        /// <returns> the new Entry, as returned from the server</returns>
        //////////////////////////////////////////////////////////////////////
        public TEntry  Update<TEntry>(TEntry entry) where TEntry : AtomEntry
        {
            return this.Update(entry, null) as TEntry;
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>WebResponse Update(Uri updateUri, Stream entryStream, ICredentials credentials)</summary> 
        /// <param name="entry">the old entry to update</param> 
        /// <param name="data">the async data block used</param> 
        /// <returns> the new Entry, as returned from the server</returns>
        //////////////////////////////////////////////////////////////////////
00567         private AtomEntry Update(AtomEntry entry, AsyncSendData data)
        {
            Tracing.Assert(entry != null, "entry should not be null");
            if (entry == null)
            {
                throw new ArgumentNullException("entry"); 
            }

            if (entry.ReadOnly == true)
            {
                throw new GDataRequestException("Can not update a read-only entry"); 
            }


            Uri target = new Uri(entry.EditUri.ToString());

            Stream returnStream = EntrySend(target, entry, GDataRequestType.Update, data);
            return CreateAndParseEntry(returnStream, target);
        }
        /////////////////////////////////////////////////////////////////////////////

   

        //////////////////////////////////////////////////////////////////////
        /// <summary>public WebResponse Insert(Uri insertUri, Stream entryStream, ICredentials credentials)</summary> 
        /// <param name="feed">the feed this entry should be inserted into</param> 
        /// <param name="entry">the entry to be inserted</param> 
        /// <returns> the inserted entry</returns>
        //////////////////////////////////////////////////////////////////////
00596         AtomEntry IService.Insert(AtomFeed feed, AtomEntry entry)
        {

            Tracing.Assert(feed != null, "feed should not be null");
            if (feed == null)
            {
                throw new ArgumentNullException("feed"); 
            }
            Tracing.Assert(entry != null, "entry should not be null");
            if (entry == null)
            {
                throw new ArgumentNullException("entry"); 
            }

            if (feed.ReadOnly == true)
            {
                throw new GDataRequestException("Can not update a read-only feed"); 
            }

            Tracing.TraceMsg("Post URI is: " + feed.Post); 
            Uri target = new Uri(feed.Post); 
            return Insert(target, entry);
        }
        /////////////////////////////////////////////////////////////////////////////
        


     
        //////////////////////////////////////////////////////////////////////
        /// <summary>
        /// templated type safe version of Insert
        /// </summary>
        /// <typeparam name="TEntry"></typeparam>
        /// <param name="feed"></param>
        /// <param name="entry"></param>
        /// <returns> the new Entry, as returned from the server</returns>
        public TEntry Insert<TEntry>(AtomFeed feed, TEntry entry) where TEntry : AtomEntry
        {
            IService s = this as IService; 
            return s.Insert(feed, entry) as TEntry;
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>templated type safe verion of the interface</summary> 
        /// <typeparam name="TEntry"></typeparam>
        /// <param name="feedUri"></param>
        /// <param name="entry">the old entry to update</param> 
        /// <returns> the new Entry, as returned from the server</returns> 
        public TEntry Insert<TEntry>(Uri feedUri, TEntry entry) where TEntry : AtomEntry
        {
            return this.Insert(feedUri, entry, null) as TEntry;
        }
        /////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// internal Insert version to avoid recursion in the template versions
        /// </summary>
        /// <param name="feedUri"></param>
        /// <param name="newEntry"></param>
        /// <returns></returns>
00657         protected AtomEntry internalInsert(Uri feedUri, AtomEntry newEntry)
        {
            return this.Insert(feedUri, newEntry, null);
        }



        //////////////////////////////////////////////////////////////////////
        /// <summary>public WebResponse Insert(Uri insertUri, Stream entryStream, ICredentials credentials)</summary> 
        /// <param name="feedUri">the uri for the feed this entry should be inserted into</param> 
        /// <param name="newEntry">the entry to be inserted</param> 
        /// <param name="data">the data used for an async request</param>
        /// <returns> the inserted entry</returns>
        //////////////////////////////////////////////////////////////////////
00671         private AtomEntry Insert(Uri feedUri, AtomEntry newEntry, AsyncSendData data)
        {
            Tracing.Assert(feedUri != null, "feedUri should not be null");
            if (feedUri == null)
            {
                throw new ArgumentNullException("feedUri"); 
            }
            Tracing.Assert(newEntry != null, "newEntry should not be null");
            if (newEntry == null)
            {
                throw new ArgumentNullException("newEntry"); 
            }
            this.versionInfo.ImprintVersion(newEntry);

            Stream returnStream = EntrySend(feedUri, newEntry, GDataRequestType.Insert, data);
            return CreateAndParseEntry(returnStream, feedUri);
        }
        /////////////////////////////////////////////////////////////////////////////



        /// <summary>
        /// simple update for media resources
        /// </summary>
        /// <param name="uriTarget"></param>
        /// <param name="input">the stream to send</param>
        /// <param name="contentType"></param>
        /// <param name="slugHeader">the value for the slug header, indicating filenaming</param>
        /// <returns>AtomEntry</returns>
00700         public AtomEntry Update(Uri uriTarget, Stream input, string contentType, string slugHeader)
        {
            Stream returnStream = StreamSend(uriTarget, input, GDataRequestType.Update, contentType, slugHeader);
            return CreateAndParseEntry(returnStream, uriTarget);
        }   

        /// <summary>
        /// Simple insert for media resources
        /// </summary>
        /// <param name="uriTarget"></param>
        /// <param name="input"></param>
        /// <param name="contentType"></param>
        /// <param name="slugHeader">the value for the slug header, indicating filenaming</param>
        /// <returns>AtomEntry</returns>
00714         public AtomEntry Insert(Uri uriTarget, Stream input, string contentType, string slugHeader)
        {
            Stream returnStream = StreamSend(uriTarget, input, GDataRequestType.Insert, contentType, slugHeader);
            return CreateAndParseEntry(returnStream, uriTarget);
        }


        private AtomFeed CreateAndParseFeed(Stream inputStream, Uri uriToUse)
        {
            AtomFeed returnFeed = null;

            if (inputStream != null)
            {
                returnFeed = CreateFeed(uriToUse);
                this.versionInfo.ImprintVersion(returnFeed);
                try
                {
                    returnFeed.NewAtomEntry += new FeedParserEventHandler(this.OnParsedNewEntry); 
                    returnFeed.NewExtensionElement += new ExtensionElementEventHandler(this.OnNewExtensionElement);
                    returnFeed.Parse(inputStream, AlternativeFormat.Atom);
                }
                finally
                {
                    inputStream.Close(); 
                }
            }

            return returnFeed; 
        }

        private AtomEntry CreateAndParseEntry(Stream inputStream, Uri uriTarget)
        {
            AtomFeed returnFeed = CreateAndParseFeed(inputStream, uriTarget);
            AtomEntry entry=null; 
            // there should be ONE entry echoed back. 
            if (returnFeed != null && returnFeed.Entries.Count > 0)
            {
                entry = returnFeed.Entries[0];
                if (entry != null)
                {
                    entry.Service = this;
                    entry.setFeed(null);
                }
            }
            return entry; 
        }
   


        //////////////////////////////////////////////////////////////////////
        /// <summary>Inserts an AtomBase entry against a Uri</summary> 
        /// <param name="feedUri">the uri for the feed this object should be posted against</param> 
        /// <param name="baseEntry">the entry to be inserted</param> 
        /// <param name="type">the type of request to create</param> 
        /// <returns> the response as a stream</returns>
        //////////////////////////////////////////////////////////////////////
00770         public Stream EntrySend(Uri feedUri, AtomEntry baseEntry, GDataRequestType type)
        {
            return this.EntrySend(feedUri, baseEntry, type, null); 
        }


        //////////////////////////////////////////////////////////////////////
        /// <summary>Inserts an AtomBase entry against a Uri</summary> 
        /// <param name="feedUri">the uri for the feed this object should be posted against</param> 
        /// <param name="baseEntry">the entry to be inserted</param> 
        /// <param name="type">the type of request to create</param> 
        /// <param name="data">the async data payload</param>
        /// <returns> the response as a stream</returns>
        //////////////////////////////////////////////////////////////////////
00784         internal virtual Stream EntrySend(Uri feedUri, AtomBase baseEntry, GDataRequestType type, AsyncSendData data)
        {
            Tracing.Assert(feedUri != null, "feedUri should not be null");
            if (feedUri == null)
            {
                throw new ArgumentNullException("feedUri"); 
            }
            Tracing.Assert(baseEntry != null, "baseEntry should not be null");
            if (baseEntry == null)
            {
                throw new ArgumentNullException("baseEntry"); 
            }
            this.versionInfo.ImprintVersion(baseEntry);

            IGDataRequest request = this.RequestFactory.CreateRequest(type,feedUri);
            request.Credentials = this.Credentials;

            ISupportsEtag eTarget = request as ISupportsEtag;
            ISupportsEtag eSource = baseEntry as ISupportsEtag;
            if (eTarget != null && eSource != null)
            {
                eTarget.Etag = eSource.Etag;
            }
            if (data != null)
            {
                GDataGAuthRequest gr = request as GDataGAuthRequest;
                if (gr != null)
                {
                    gr.AsyncData = data;
                }
            }

            Stream outputStream = request.GetRequestStream();

            baseEntry.SaveToXml(outputStream);
            request.Execute();

            outputStream.Close();
            return request.GetResponseStream();
        }



        /// <summary>
        /// this is a helper function for external utilities. It is not worth
        /// running the other insert/saves through here, as this would involve
        /// double buffering/copying of the bytes
        /// </summary>
        /// <param name="targetUri"></param>
        /// <param name="payload"></param>
        /// <param name="type"></param>
        /// <returns>Stream</returns>
        
00837         public Stream StringSend(Uri targetUri, String payload, GDataRequestType type)
        {
            Tracing.Assert(targetUri != null, "targetUri should not be null");
            if (targetUri == null)
            {
                throw new ArgumentNullException("targetUri"); 
            }
            Tracing.Assert(payload != null, "payload should not be null");
            if (payload == null)
            {
                throw new ArgumentNullException("payload"); 
            }

            IGDataRequest request = this.RequestFactory.CreateRequest(type,targetUri);
            request.Credentials = this.Credentials;

            Stream outputStream = request.GetRequestStream();

            StreamWriter w = new StreamWriter(outputStream);
            w.Write(payload);
            w.Flush();
       
            request.Execute();

            w.Close();
            return request.GetResponseStream();
        }



        /// <summary>
        /// this is a helper function for to send binary data to a resource
        /// it is not worth running the other insert/saves through here, as this would involve
        /// double buffering/copying of the bytes
        /// </summary>
        /// <param name="targetUri"></param>
        /// <param name="inputStream"></param>
        /// <param name="type"></param>
        /// <param name="contentType">the contenttype to use in the request, if NULL is passed, factory default is used</param>
        /// <param name="slugHeader">the slugHeader to use in the request, if NULL is passed, factory default is used</param>
        /// <returns>Stream</returns>
00878         public Stream StreamSend(Uri targetUri, 
                                 Stream inputStream, 
                                 GDataRequestType type, 
                                 string contentType,
                                 string slugHeader)
        {

            return StreamSend(targetUri, inputStream, type, contentType, slugHeader, null, null);
        }

        /// <summary>
        /// this is a helper function for to send binary data to a resource
        /// it is not worth running the other insert/saves through here, as this would involve
        /// double buffering/copying of the bytes
        /// </summary>
        /// <param name="targetUri"></param>
        /// <param name="inputStream"></param>
        /// <param name="type"></param>
        /// <param name="contentType">the contenttype to use in the request, if NULL is passed, factory default is used</param>
        /// <param name="slugHeader">the slugHeader to use in the request, if NULL is passed, factory default is used</param>
        /// <param name="etag">The http etag to pass into the request</param>
        /// <returns>Stream</returns>
00900         public Stream StreamSend(Uri targetUri, 
                                 Stream inputStream, 
                                 GDataRequestType type, 
                                 string contentType,
                                 string slugHeader,
                                 string etag)
        {

            return StreamSend(targetUri, inputStream, type, contentType, slugHeader, etag, null);
        }


        /// <summary>
        /// this is a helper function for to send binary data to a resource
        /// it is not worth running the other insert/saves through here, as this would involve
        /// double buffering/copying of the bytes
        /// </summary>
        /// <param name="targetUri"></param>
        /// <param name="inputStream"></param>
        /// <param name="type"></param>
        /// <param name="contentType">the contenttype to use in the request, if NULL is passed, factory default is used</param>
        /// <param name="slugHeader">the slugHeader to use in the request, if NULL is passed, factory default is used</param>
        /// <param name="etag">The http etag to pass into the request</param>
        /// <param name="data">The async data needed for notifications</param>
        /// <returns>Stream from the server response. You should close this stream explicitly.</returns>
00925         private Stream StreamSend(Uri targetUri, 
                                 Stream inputStream, 
                                 GDataRequestType type, 
                                 string contentType,
                                 string slugHeader,
                                 string etag,
                                 AsyncSendData data)
        {
            Tracing.Assert(targetUri != null, "targetUri should not be null");
            if (targetUri == null)
            {
                throw new ArgumentNullException("targetUri"); 
            }
            if (inputStream == null)
            {
                Tracing.Assert(inputStream != null, "payload should not be null");
                throw new ArgumentNullException("inputStream"); 
            }
            if (type != GDataRequestType.Insert && type != GDataRequestType.Update)
            {
                Tracing.Assert(type != GDataRequestType.Insert && type != GDataRequestType.Update,"type needs to be insert or update");
                throw new ArgumentNullException("type"); 
            }


            IGDataRequest request = this.RequestFactory.CreateRequest(type,targetUri);
            request.Credentials = this.Credentials;

            if (data != null)
            {
                GDataGAuthRequest gr = request as GDataGAuthRequest;
                if (gr != null)
                {
                    gr.AsyncData = data;
                }
            }

            // set the contenttype of the request
            if (contentType != null)
            {
                GDataRequest r = request as GDataRequest;
                if (r != null)
                {
                    r.ContentType = contentType;
                }
            }

            if (slugHeader != null)
            {
                GDataRequest r = request as GDataRequest;
                if (r != null)
                {
                    r.Slug = slugHeader;
                }
            }

            if (etag != null)
            {
                ISupportsEtag ise = request as ISupportsEtag;
                if (ise != null)
                {
                    ise.Etag = etag;
                }
            }

            Stream outputStream = request.GetRequestStream();

            WriteInputStreamToRequest(inputStream, outputStream);

            request.Execute();
            outputStream.Close();
            return new GDataReturnStream(request);
        }

        /// <summary>
        /// write the current stream to an output stream
        /// this is primarily used to write data to the 
        /// request stream
        /// </summary>
        /// <param name="input"></param>
        /// <param name="output"></param>
01006         protected void WriteInputStreamToRequest(Stream input, Stream output)
        {
            BinaryWriter w = new BinaryWriter(output);
            const int size = 4096;
            byte[] bytes = new byte[4096];
            int numBytes;

            while((numBytes = input.Read(bytes, 0, size)) > 0)
            {
                w.Write(bytes, 0, numBytes);
            }
            w.Flush();
        }


        //////////////////////////////////////////////////////////////////////
        /// <summary>creates a new feed instance to be returned by
        /// Batch(), Query() and other operations
        ///
        /// Subclasses can supply their own feed implementation by
        /// overriding this method.
        /// </summary>
        //////////////////////////////////////////////////////////////////////
01029         protected virtual AtomFeed CreateFeed(Uri uriToUse)
        {
            ServiceEventArgs args = null;
            AtomFeed feed = null;

            if (this.NewFeed != null)
            {
                args = new ServiceEventArgs(uriToUse, this);
                this.NewFeed(this, args);
            }

            if (args != null)
            {
                feed = args.Feed;
            }

            if (feed == null)
            {
                feed = new AtomFeed(uriToUse, this);
            }

            return feed;
        }


        /// <summary>
        /// takes a given feed, and does a batch post of that feed
        /// against the batchUri parameter. If that one is NULL 
        /// it will try to use the batch link URI in the feed
        /// </summary>
        /// <param name="feed">the feed to post</param>
        /// <param name="batchUri">the URI to user</param>
        /// <returns>the returned AtomFeed</returns>
01062         public AtomFeed Batch(AtomFeed feed, Uri batchUri) 
        {
            return Batch(feed, batchUri, null);
        }
        //////////////////////////////////////////////////////////////////////



        /// <summary>
        /// takes a given feed, and does a batch post of that feed
        /// against the batchUri parameter. If that one is NULL 
        /// it will try to use the batch link URI in the feed
        /// </summary>
        /// <param name="feed">the feed to post</param>
        /// <param name="batchUri">the URI to user</param>
        /// <param name="data">The async data payload</param>
        /// <returns>the returned AtomFeed</returns>
01079         private AtomFeed Batch(AtomFeed feed, Uri batchUri, AsyncSendData data) 
        {
            Uri uriToUse = batchUri;
            if (feed == null)
            {
                throw new ArgumentNullException("feed");
            }

            if (uriToUse == null)
            {
                uriToUse = feed.Batch == null ? null : new Uri(feed.Batch); 
            }

            if (uriToUse == null)
            {
                throw new ArgumentNullException("batchUri"); 
            }

            Tracing.Assert(feed != null, "feed should not be null");
            if (feed == null)
            {
                throw new ArgumentNullException("feed"); 
            }

            if (feed.BatchData == null) 
            {
                // setting this will make the feed output the namespace, instead of each entry
                feed.BatchData = new GDataBatchFeedData(); 
            }  
            Stream returnStream = EntrySend(uriToUse, feed, GDataRequestType.Batch, data);
            return CreateAndParseFeed(returnStream, uriToUse);;  
        }
        //////////////////////////////////////////////////////////////////////



    
        //////////////////////////////////////////////////////////////////////
        /// <summary>deletes an Atom entry object</summary> 
        /// <param name="entry"> </param>
        //////////////////////////////////////////////////////////////////////
01120         public void Delete(AtomEntry entry)
        {
            Tracing.Assert(entry != null, "entry should not be null");
            string eTag = null;

            if (entry == null)
            {
                throw new ArgumentNullException("entry"); 
            }

            if (entry.ReadOnly == true)
            {
                throw new GDataRequestException("Can not update a read-only entry"); 
            }

            Tracing.Assert(entry.EditUri != null, "Entry should have a valid edit URI"); 

            ISupportsEtag eSource = entry as ISupportsEtag;

            if (eSource != null)
            {
                eTag = eSource.Etag;
            }

            if (entry.EditUri != null)
            {
                Delete(new Uri(entry.EditUri.ToString()), eTag);
            }
            else
            {
                throw new GDataRequestException("Invalid Entry object (no edit uri) to call Delete on"); 
            }
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        ///<summary>Deletes an Atom entry when given a Uri</summary>
        ///<param name="uriTarget">The target Uri to call http delete against</param>
        /////////////////////////////////////////////////////////////////////
01159         public void Delete(Uri uriTarget)
        {
            Delete(uriTarget, null);
        }   
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        ///<summary>Deletes an Atom entry when given a Uri</summary>
        ///<param name="uriTarget">The target Uri to call http delete against</param>
        ///<param name="eTag">The eTag of the item to delete. This parameter is used for strong
        /// concurrency support in protocol version 2 and up</param>
        /////////////////////////////////////////////////////////////////////
01172         public void Delete(Uri uriTarget, string eTag)
        {
            Tracing.Assert(uriTarget != null, "uri should not be null");
            if (uriTarget == null)
            {
                throw new ArgumentNullException("uriTarget");
            }

            Tracing.TraceMsg("Deleting entry: " + uriTarget.ToString());
            IGDataRequest request = RequestFactory.CreateRequest(GDataRequestType.Delete, uriTarget);

            ISupportsEtag eTarget = request as ISupportsEtag;
            if (eTarget != null && eTag != null)
            {
                eTarget.Etag = eTag;
            }

            request.Credentials = Credentials;
            request.Execute();
            IDisposable disp = request as IDisposable;
            disp.Dispose();
        }   
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>eventchaining. We catch this by the baseFeedParsers, which 
        /// would not do anything with the gathered data. We pass the event up
        /// to the user</summary> 
        /// <param name="sender"> the object which send the event</param>
        /// <param name="e">FeedParserEventArguments, holds the feedentry</param> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
01205         protected void OnParsedNewEntry(object sender, FeedParserEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e"); 
            }
            if (this.NewAtomEntry != null)
            {
                // just forward it upstream, if hooked
                Tracing.TraceMsg("\t calling event dispatcher"); 
                this.NewAtomEntry(this, e);
            }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>eventchaining. We catch this by the baseFeedParsers, which 
        /// would not do anything with the gathered data. We pass the event up
        /// to the user, and if he did not dicscard it, we add the entry to our
        /// collection</summary> 
        /// <param name="sender"> the object which send the event</param>
        /// <param name="e">FeedParserEventArguments, holds the feedentry</param> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
01230         protected void OnNewExtensionElement(object sender, ExtensionElementEventArgs e)
        {
            // by default, if our event chain is not hooked, the underlying parser will add it
            Tracing.TraceCall("received new extension element notification");
            Tracing.Assert(e != null, "e should not be null");
            if (e == null)
            {
                throw new ArgumentNullException("e"); 
            }
            if (this.NewExtensionElement != null)
            {
                Tracing.TraceMsg("\t calling event dispatcher"); 
                this.NewExtensionElement(this, e);
            }
        }
        /////////////////////////////////////////////////////////////////////////////


    }
    /////////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// used to cover a return stream and add some additional data to it. 
    /// </summary>
01254     public class GDataReturnStream : Stream, ISupportsEtag
    {
        private string etag;
        private Stream innerStream;

        /// <summary>
        /// default constructor based on a gdatarequest object
        /// </summary>
        /// <param name="r"></param>
01263         public GDataReturnStream(IGDataRequest r)
        {
            this.innerStream = r.GetResponseStream();
            ISupportsEtag ise = r as ISupportsEtag;
            if (ise != null)
            {
                this.etag = ise.Etag;
            }
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        public override bool CanRead
01277         {
            get { return this.innerStream.CanRead; }
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        public override bool CanSeek
01285         {
            get { return this.innerStream.CanSeek; }
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        public override bool CanTimeout
01293         {
            get { return this.innerStream.CanTimeout;}
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
01300         public override void Close()
        {
            this.innerStream.Close();
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        public override bool CanWrite
01309         {
            get { return this.innerStream.CanWrite; }
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        public override long Length
01317         {
            get { return this.innerStream.Length; }
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        public override long Position
01325         {
            get
            {
                return this.innerStream.Position;
            }
            set
            {
                this.innerStream.Position = value;
            }
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
01339         public override void Flush()
        {
            this.innerStream.Flush();
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        /// <param name="offset"></param>
        /// <param name="origin"></param>
01349         public override long Seek(long offset, SeekOrigin origin)
        {
            return this.innerStream.Seek(offset, origin);
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        /// <param name="value"></param>
01358         public override void SetLength(long value)
        {
            this.innerStream.SetLength(value);
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="count"/>
        /// <param name="offset"/>
01369         public override int Read(byte[] buffer, int offset, int count)
        {
            return this.innerStream.Read(buffer, offset, count);           
        }

        /// <summary>
        /// default override, delegates to the real stream
        /// </summary>
        /// <param name="buffer"/>
        /// <param name="count"/>
        /// <param name="offset"/>
01380         public override void Write(byte[] buffer, int offset, int count)
        {
            this.innerStream.Write(buffer, offset, count);
        }

        /// <summary>
        /// implements the etag interface
        /// </summary>
        public string Etag
01389         {
            get { return this.etag; }
            set { this.etag = value; }
        }
    }
} 
/////////////////////////////////////////////////////////////////////////////

Generated by  Doxygen 1.6.0   Back to index