Back to index

lightning-sunbird  0.9+nobinonly
nsRDFContainerUtils.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040 
00041   Implementation for the RDF container utils.
00042 
00043  */
00044 
00045 
00046 #include "nsCOMPtr.h"
00047 #include "nsIServiceManager.h"
00048 #include "nsIRDFContainer.h"
00049 #include "nsIRDFContainerUtils.h"
00050 #include "nsIRDFService.h"
00051 #include "nsRDFCID.h"
00052 #include "nsString.h"
00053 #include "nsXPIDLString.h"
00054 #include "plstr.h"
00055 #include "prprf.h"
00056 #include "rdf.h"
00057 #include "rdfutil.h"
00058 
00059 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00060 static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
00061 
00062 class RDFContainerUtilsImpl : public nsIRDFContainerUtils
00063 {
00064 public:
00065     // nsISupports interface
00066     NS_DECL_ISUPPORTS
00067 
00068     // nsIRDFContainerUtils interface
00069     NS_DECL_NSIRDFCONTAINERUTILS
00070 
00071 private:
00072     friend nsresult NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult);
00073 
00074     RDFContainerUtilsImpl();
00075     virtual ~RDFContainerUtilsImpl();
00076 
00077     nsresult MakeContainer(nsIRDFDataSource* aDataSource,
00078                            nsIRDFResource* aResource,
00079                            nsIRDFResource* aType,
00080                            nsIRDFContainer** aResult);
00081 
00082     PRBool IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType);
00083 
00084     // pseudo constants
00085     static PRInt32 gRefCnt;
00086     static nsIRDFService* gRDFService;
00087     static nsIRDFResource* kRDF_instanceOf;
00088     static nsIRDFResource* kRDF_nextVal;
00089     static nsIRDFResource* kRDF_Bag;
00090     static nsIRDFResource* kRDF_Seq;
00091     static nsIRDFResource* kRDF_Alt;
00092     static nsIRDFLiteral* kOne;
00093 };
00094 
00095 
00096 PRInt32         RDFContainerUtilsImpl::gRefCnt = 0;
00097 nsIRDFService*  RDFContainerUtilsImpl::gRDFService;
00098 nsIRDFResource* RDFContainerUtilsImpl::kRDF_instanceOf;
00099 nsIRDFResource* RDFContainerUtilsImpl::kRDF_nextVal;
00100 nsIRDFResource* RDFContainerUtilsImpl::kRDF_Bag;
00101 nsIRDFResource* RDFContainerUtilsImpl::kRDF_Seq;
00102 nsIRDFResource* RDFContainerUtilsImpl::kRDF_Alt;
00103 nsIRDFLiteral*  RDFContainerUtilsImpl::kOne;
00104 
00106 // nsISupports interface
00107 
00108 NS_IMPL_THREADSAFE_ISUPPORTS1(RDFContainerUtilsImpl, nsIRDFContainerUtils)
00109 
00110 
00111 // nsIRDFContainerUtils interface
00112 
00113 NS_IMETHODIMP
00114 RDFContainerUtilsImpl::IsOrdinalProperty(nsIRDFResource *aProperty, PRBool *_retval)
00115 {
00116     NS_PRECONDITION(aProperty != nsnull, "null ptr");
00117     if (! aProperty)
00118         return NS_ERROR_NULL_POINTER;
00119 
00120     nsresult rv;
00121 
00122     const char       *propertyStr;
00123     rv = aProperty->GetValueConst( &propertyStr );
00124     if (NS_FAILED(rv)) return rv;
00125 
00126     if (PL_strncmp(propertyStr, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
00127         *_retval = PR_FALSE;
00128         return NS_OK;
00129     }
00130 
00131     const char* s = propertyStr;
00132     s += sizeof(kRDFNameSpaceURI) - 1;
00133     if (*s != '_') {
00134         *_retval = PR_FALSE;
00135         return NS_OK;
00136     }
00137 
00138     ++s;
00139     while (*s) {
00140         if (*s < '0' || *s > '9') {
00141             *_retval = PR_FALSE;
00142             return NS_OK;
00143         }
00144 
00145         ++s;
00146     }
00147 
00148     *_retval = PR_TRUE;
00149     return NS_OK;
00150 }
00151 
00152 
00153 NS_IMETHODIMP
00154 RDFContainerUtilsImpl::IndexToOrdinalResource(PRInt32 aIndex, nsIRDFResource **aOrdinal)
00155 {
00156     NS_PRECONDITION(aIndex > 0, "illegal value");
00157     if (aIndex <= 0)
00158         return NS_ERROR_ILLEGAL_VALUE;
00159 
00160     nsCAutoString uri(kRDFNameSpaceURI);
00161     uri.Append('_');
00162     uri.AppendInt(aIndex);
00163     
00164     nsresult rv = gRDFService->GetResource(uri, aOrdinal);
00165     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get ordinal resource");
00166     if (NS_FAILED(rv)) return rv;
00167     
00168     return NS_OK;
00169 }
00170 
00171 
00172 NS_IMETHODIMP
00173 RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource *aOrdinal, PRInt32 *aIndex)
00174 {
00175     NS_PRECONDITION(aOrdinal != nsnull, "null ptr");
00176     if (! aOrdinal)
00177         return NS_ERROR_NULL_POINTER;
00178 
00179     const char       *ordinalStr;
00180     if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr )))
00181         return NS_ERROR_FAILURE;
00182 
00183     const char* s = ordinalStr;
00184     if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
00185         NS_ERROR("not an ordinal");
00186         return NS_ERROR_UNEXPECTED;
00187     }
00188 
00189     s += sizeof(kRDFNameSpaceURI) - 1;
00190     if (*s != '_') {
00191         NS_ERROR("not an ordinal");
00192         return NS_ERROR_UNEXPECTED;
00193     }
00194 
00195     PRInt32 idx = 0;
00196 
00197     ++s;
00198     while (*s) {
00199         if (*s < '0' || *s > '9') {
00200             NS_ERROR("not an ordinal");
00201             return NS_ERROR_UNEXPECTED;
00202         }
00203 
00204         idx *= 10;
00205         idx += (*s - '0');
00206 
00207         ++s;
00208     }
00209 
00210     *aIndex = idx;
00211     return NS_OK;
00212 }
00213 
00214 NS_IMETHODIMP
00215 RDFContainerUtilsImpl::IsContainer(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, PRBool *_retval)
00216 {
00217     NS_PRECONDITION(aDataSource != nsnull, "null ptr");
00218     if (! aDataSource)
00219         return NS_ERROR_NULL_POINTER;
00220 
00221     NS_PRECONDITION(aResource != nsnull, "null ptr");
00222     if (! aResource)
00223         return NS_ERROR_NULL_POINTER;
00224 
00225     NS_PRECONDITION(_retval != nsnull, "null ptr");
00226     if (! _retval)
00227         return NS_ERROR_NULL_POINTER;
00228 
00229     if (IsA(aDataSource, aResource, kRDF_Seq) ||
00230         IsA(aDataSource, aResource, kRDF_Bag) ||
00231         IsA(aDataSource, aResource, kRDF_Alt)) {
00232         *_retval = PR_TRUE;
00233     }
00234     else {
00235         *_retval = PR_FALSE;
00236     }
00237     return NS_OK;
00238 }
00239 
00240 
00241 NS_IMETHODIMP
00242 RDFContainerUtilsImpl::IsEmpty(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, PRBool* _retval)
00243 {
00244     if (! aDataSource)
00245         return NS_ERROR_NULL_POINTER;
00246 
00247     nsresult rv;
00248 
00249     // By default, say that we're an empty container. Even if we're not
00250     // really even a container.
00251     *_retval = PR_TRUE;
00252 
00253     nsCOMPtr<nsIRDFNode> nextValNode;
00254     rv = aDataSource->GetTarget(aResource, kRDF_nextVal, PR_TRUE, getter_AddRefs(nextValNode));
00255     if (NS_FAILED(rv)) return rv;
00256 
00257     if (rv == NS_RDF_NO_VALUE)
00258         return NS_OK;
00259 
00260     nsCOMPtr<nsIRDFLiteral> nextValLiteral;
00261     rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
00262     if (NS_FAILED(rv)) return rv;
00263 
00264     if (nextValLiteral.get() != kOne)
00265         *_retval = PR_FALSE;
00266 
00267     return NS_OK;
00268 }
00269 
00270 
00271 NS_IMETHODIMP
00272 RDFContainerUtilsImpl::IsBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, PRBool *_retval)
00273 {
00274     NS_PRECONDITION(aDataSource != nsnull, "null ptr");
00275     if (! aDataSource)
00276         return NS_ERROR_NULL_POINTER;
00277 
00278     NS_PRECONDITION(aResource != nsnull, "null ptr");
00279     if (! aResource)
00280         return NS_ERROR_NULL_POINTER;
00281 
00282     NS_PRECONDITION(_retval != nsnull, "null ptr");
00283     if (! _retval)
00284         return NS_ERROR_NULL_POINTER;
00285 
00286     *_retval = IsA(aDataSource, aResource, kRDF_Bag);
00287     return NS_OK;
00288 }
00289 
00290 
00291 NS_IMETHODIMP
00292 RDFContainerUtilsImpl::IsSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, PRBool *_retval)
00293 {
00294     NS_PRECONDITION(aDataSource != nsnull, "null ptr");
00295     if (! aDataSource)
00296         return NS_ERROR_NULL_POINTER;
00297 
00298     NS_PRECONDITION(aResource != nsnull, "null ptr");
00299     if (! aResource)
00300         return NS_ERROR_NULL_POINTER;
00301 
00302     NS_PRECONDITION(_retval != nsnull, "null ptr");
00303     if (! _retval)
00304         return NS_ERROR_NULL_POINTER;
00305 
00306     *_retval = IsA(aDataSource, aResource, kRDF_Seq);
00307     return NS_OK;
00308 }
00309 
00310 
00311 NS_IMETHODIMP
00312 RDFContainerUtilsImpl::IsAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, PRBool *_retval)
00313 {
00314     NS_PRECONDITION(aDataSource != nsnull, "null ptr");
00315     if (! aDataSource)
00316         return NS_ERROR_NULL_POINTER;
00317 
00318     NS_PRECONDITION(aResource != nsnull, "null ptr");
00319     if (! aResource)
00320         return NS_ERROR_NULL_POINTER;
00321 
00322     NS_PRECONDITION(_retval != nsnull, "null ptr");
00323     if (! _retval)
00324         return NS_ERROR_NULL_POINTER;
00325 
00326     *_retval = IsA(aDataSource, aResource, kRDF_Alt);
00327     return NS_OK;
00328 }
00329 
00330 
00331 NS_IMETHODIMP
00332 RDFContainerUtilsImpl::MakeBag(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
00333 {
00334     return MakeContainer(aDataSource, aResource, kRDF_Bag, _retval);
00335 }
00336 
00337 
00338 NS_IMETHODIMP
00339 RDFContainerUtilsImpl::MakeSeq(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
00340 {
00341     return MakeContainer(aDataSource, aResource, kRDF_Seq, _retval);
00342 }
00343 
00344 
00345 NS_IMETHODIMP
00346 RDFContainerUtilsImpl::MakeAlt(nsIRDFDataSource *aDataSource, nsIRDFResource *aResource, nsIRDFContainer **_retval)
00347 {
00348     return MakeContainer(aDataSource, aResource, kRDF_Alt, _retval);
00349 }
00350 
00351 
00352 
00354 
00355 
00356 RDFContainerUtilsImpl::RDFContainerUtilsImpl()
00357 {
00358     if (gRefCnt++ == 0) {
00359         nsresult rv;
00360 
00361         rv = CallGetService(kRDFServiceCID, &gRDFService);
00362 
00363         NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
00364         if (NS_SUCCEEDED(rv)) {
00365             gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
00366                                      &kRDF_instanceOf);
00367             gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
00368                                      &kRDF_nextVal);
00369             gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
00370                                      &kRDF_Bag);
00371             gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
00372                                      &kRDF_Seq);
00373             gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
00374                                      &kRDF_Alt);
00375             gRDFService->GetLiteral(NS_LITERAL_STRING("1").get(), &kOne);
00376         }
00377     }
00378 }
00379 
00380 
00381 RDFContainerUtilsImpl::~RDFContainerUtilsImpl()
00382 {
00383 #ifdef DEBUG_REFS
00384     --gInstanceCount;
00385     fprintf(stdout, "%d - RDF: RDFContainerUtilsImpl\n", gInstanceCount);
00386 #endif
00387 
00388     if (--gRefCnt == 0) {
00389         NS_IF_RELEASE(gRDFService);
00390         NS_IF_RELEASE(kRDF_instanceOf);
00391         NS_IF_RELEASE(kRDF_nextVal);
00392         NS_IF_RELEASE(kRDF_Bag);
00393         NS_IF_RELEASE(kRDF_Seq);
00394         NS_IF_RELEASE(kRDF_Alt);
00395         NS_IF_RELEASE(kOne);
00396     }
00397 }
00398 
00399 
00400 
00401 nsresult
00402 NS_NewRDFContainerUtils(nsIRDFContainerUtils** aResult)
00403 {
00404     NS_PRECONDITION(aResult != nsnull, "null ptr");
00405     if (! aResult)
00406         return NS_ERROR_NULL_POINTER;
00407 
00408     RDFContainerUtilsImpl* result =
00409         new RDFContainerUtilsImpl();
00410 
00411     if (! result)
00412         return NS_ERROR_OUT_OF_MEMORY;
00413 
00414     NS_ADDREF(result);
00415     *aResult = result;
00416     return NS_OK;
00417 }
00418 
00419 
00420 nsresult
00421 RDFContainerUtilsImpl::MakeContainer(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType, nsIRDFContainer** aResult)
00422 {
00423     NS_PRECONDITION(aDataSource != nsnull, "null ptr");
00424     if (! aDataSource)      return NS_ERROR_NULL_POINTER;
00425 
00426     NS_PRECONDITION(aResource != nsnull, "null ptr");
00427     if (! aResource) return NS_ERROR_NULL_POINTER;
00428 
00429     NS_PRECONDITION(aType != nsnull, "null ptr");
00430     if (! aType)     return NS_ERROR_NULL_POINTER;
00431 
00432     if (aResult)     *aResult = nsnull;
00433 
00434     nsresult rv;
00435 
00436     // Check to see if somebody has already turned it into a container; if so
00437     // don't try to do it again.
00438     PRBool isContainer;
00439     rv = IsContainer(aDataSource, aResource, &isContainer);
00440     if (NS_FAILED(rv)) return rv;
00441 
00442     if (isContainer == PR_FALSE)
00443     {
00444        rv = aDataSource->Assert(aResource, kRDF_instanceOf, aType, PR_TRUE);
00445        if (NS_FAILED(rv)) return rv;
00446 
00447        rv = aDataSource->Assert(aResource, kRDF_nextVal, kOne, PR_TRUE);
00448        if (NS_FAILED(rv)) return rv;
00449     }
00450 
00451     if (aResult) {
00452         rv = NS_NewRDFContainer(aResult);
00453         if (NS_FAILED(rv)) return rv;
00454 
00455         rv = (*aResult)->Init(aDataSource, aResource);
00456         if (NS_FAILED(rv)) return rv;
00457     }
00458 
00459     return NS_OK;
00460 }
00461 
00462 PRBool
00463 RDFContainerUtilsImpl::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType)
00464 {
00465     if (!aDataSource || !aResource || !aType)
00466         return NS_ERROR_NULL_POINTER;
00467 
00468     nsresult rv;
00469 
00470     PRBool result;
00471     rv = aDataSource->HasAssertion(aResource, kRDF_instanceOf, aType, PR_TRUE, &result);
00472     if (NS_FAILED(rv)) return PR_FALSE;
00473 
00474     return result;
00475 }
00476 
00477 NS_IMETHODIMP
00478 RDFContainerUtilsImpl::IndexOf(nsIRDFDataSource* aDataSource, nsIRDFResource* aContainer, nsIRDFNode* aElement, PRInt32* aIndex)
00479 {
00480     if (!aDataSource || !aContainer)
00481         return NS_ERROR_NULL_POINTER;
00482 
00483     // Assume we can't find it.
00484     *aIndex = -1;
00485 
00486     // If the resource is null, bail quietly
00487     if (! aElement)
00488       return NS_OK;
00489 
00490     // We'll assume that fan-out is much higher than fan-in, so grovel
00491     // through the inbound arcs, look for an ordinal resource, and
00492     // decode it.
00493     nsCOMPtr<nsISimpleEnumerator> arcsIn;
00494     aDataSource->ArcLabelsIn(aElement, getter_AddRefs(arcsIn));
00495     if (! arcsIn)
00496         return NS_OK;
00497 
00498     while (1) {
00499         PRBool hasMoreArcs = PR_FALSE;
00500         arcsIn->HasMoreElements(&hasMoreArcs);
00501         if (! hasMoreArcs)
00502             break;
00503 
00504         nsCOMPtr<nsISupports> isupports;
00505         arcsIn->GetNext(getter_AddRefs(isupports));
00506         if (! isupports)
00507             break;
00508 
00509         nsCOMPtr<nsIRDFResource> property =
00510             do_QueryInterface(isupports);
00511 
00512         if (! property)
00513             continue;
00514 
00515         PRBool isOrdinal;
00516         IsOrdinalProperty(property, &isOrdinal);
00517         if (! isOrdinal)
00518             continue;
00519 
00520         nsCOMPtr<nsISimpleEnumerator> sources;
00521         aDataSource->GetSources(property, aElement, PR_TRUE, getter_AddRefs(sources));
00522         if (! sources)
00523             continue;
00524 
00525         while (1) {
00526             PRBool hasMoreSources = PR_FALSE;
00527             sources->HasMoreElements(&hasMoreSources);
00528             if (! hasMoreSources)
00529                 break;
00530 
00531             nsCOMPtr<nsISupports> isupports2;
00532             sources->GetNext(getter_AddRefs(isupports2));
00533             if (! isupports2)
00534                 break;
00535 
00536             nsCOMPtr<nsIRDFResource> source =
00537                 do_QueryInterface(isupports2);
00538 
00539             if (source == aContainer)
00540                 // Found it.
00541                 return OrdinalResourceToIndex(property, aIndex);
00542         }
00543     }
00544 
00545     return NS_OK;
00546 }