001    /*
002     * Copyright 2011-2012 UnboundID Corp.
003     *
004     * This program is free software; you can redistribute it and/or modify
005     * it under the terms of the GNU General Public License (GPLv2 only)
006     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
007     * as published by the Free Software Foundation.
008     *
009     * This program is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012     * GNU General Public License for more details.
013     *
014     * You should have received a copy of the GNU General Public License
015     * along with this program; if not, see <http://www.gnu.org/licenses>.
016     */
017    
018    package com.unboundid.scim.sdk;
019    
020    import com.unboundid.scim.data.BaseResource;
021    import com.unboundid.scim.data.Meta;
022    import com.unboundid.scim.schema.ResourceDescriptor;
023    
024    import javax.ws.rs.core.UriBuilder;
025    import java.net.URI;
026    import java.util.ArrayList;
027    import java.util.Collection;
028    import java.util.List;
029    
030    /**
031     * This class provides an implementation of the SCIM server backend API that
032     * serves up the resource schema from a collection of ResourceDescriptors.
033     */
034    public class ResourceSchemaBackend extends SCIMBackend
035    {
036      private final Collection<ResourceDescriptor> resourceDescriptors;
037    
038      /**
039       * Create a new ResourceSchemaBackend that serves up the schema provided
040       * from the ResourceDescriptors.
041       *
042       * @param resourceDescriptors The ResourceDescriptors to serve.
043       */
044      public ResourceSchemaBackend(
045          final Collection<ResourceDescriptor> resourceDescriptors) {
046        this.resourceDescriptors = resourceDescriptors;
047      }
048    
049      /**
050       * {@inheritDoc}
051       */
052      @Override
053      public boolean authenticate(final String userID, final String password) {
054        return false;
055      }
056    
057      /**
058       * {@inheritDoc}
059       */
060      @Override
061      public void finalizeBackend() {
062        resourceDescriptors.clear();
063      }
064    
065      /**
066       * {@inheritDoc}
067       */
068      @Override
069      public ResourceDescriptor getResource(final GetResourceRequest request)
070          throws SCIMException {
071        ResourceDescriptor resourceDescriptor = null;
072        for(ResourceDescriptor rd : resourceDescriptors)
073        {
074          String id = rd.getSchema() +
075              SCIMConstants.SEPARATOR_CHAR_QUALIFIED_ATTRIBUTE + rd.getName();
076          if(id.equalsIgnoreCase(request.getResourceID()))
077          {
078            resourceDescriptor = rd;
079            break;
080          }
081        }
082    
083        // Try to find a match in case the schema name was not provided.
084        if (resourceDescriptor == null)
085        {
086          for(ResourceDescriptor rd : resourceDescriptors)
087          {
088            if(rd.getName().equalsIgnoreCase(request.getResourceID()))
089            {
090              resourceDescriptor = rd;
091              break;
092            }
093          }
094        }
095    
096        if(resourceDescriptor == null)
097        {
098          throw new ResourceNotFoundException("No Resource Schema with ID " +
099              request.getResourceID() + " exists");
100        }
101    
102        return copyAndSetIdAndMetaAttributes(resourceDescriptor, request);
103      }
104    
105      /**
106       * {@inheritDoc}
107       */
108      @Override
109      public Resources getResources(final GetResourcesRequest request)
110          throws SCIMException {
111        List<BaseResource> rds =
112            new ArrayList<BaseResource>(this.resourceDescriptors.size());
113    
114        for(ResourceDescriptor resourceDescriptor : this.resourceDescriptors)
115        {
116          ResourceDescriptor copy =
117              copyAndSetIdAndMetaAttributes(resourceDescriptor, request);
118          if(request.getFilter() == null ||
119              copy.getScimObject().matchesFilter(request.getFilter()))
120          {
121            rds.add(copy);
122          }
123        }
124    
125        int fromIndex = 0;
126        int total = rds.size();
127        if(request.getPageParameters() != null)
128        {
129          fromIndex = (int)request.getPageParameters().getStartIndex() - 1;
130          int endIndex =
131              Math.min(request.getPageParameters().getCount() + fromIndex,
132                       rds.size());
133          rds = rds.subList(fromIndex, endIndex);
134        }
135    
136        return new Resources<BaseResource>(rds, total, fromIndex + 1);
137      }
138    
139      /**
140       * {@inheritDoc}
141       */
142      @Override
143      public BaseResource postResource(final PostResourceRequest request)
144          throws SCIMException {
145        throw new UnsupportedOperationException("POST operations are not allowed " +
146            "on the Resource Schema");
147      }
148    
149      /**
150       * {@inheritDoc}
151       */
152      @Override
153      public void deleteResource(final DeleteResourceRequest request)
154          throws SCIMException {
155        throw new UnsupportedOperationException("DELETE operations are not " +
156            "allowed on the Resource Schema");
157      }
158    
159      /**
160       * {@inheritDoc}
161       */
162      @Override
163      public BaseResource putResource(final PutResourceRequest request)
164          throws SCIMException {
165        throw new UnsupportedOperationException("PUT operations are not allowed " +
166            "on the Resource Schema");
167      }
168    
169    
170      /**
171       * Make a copy of the ResourceDescriptor and set the id and meta attributes
172       * from the provided information.
173       *
174       * @param resource  The SCIM object whose id and meta attributes are to be
175       *                    set.
176       * @param request   The SCIM request.
177       * @return          The copy of the ResourceDescriptor.
178       */
179      public static ResourceDescriptor copyAndSetIdAndMetaAttributes(
180          final ResourceDescriptor resource,
181          final ResourceReturningRequest request)
182      {
183        ResourceDescriptor copy =
184            ResourceDescriptor.RESOURCE_DESCRIPTOR_FACTORY.createResource(
185                resource.getResourceDescriptor(),
186                new SCIMObject(resource.getScimObject()));
187    
188        String id = resource.getSchema() +
189            SCIMConstants.SEPARATOR_CHAR_QUALIFIED_ATTRIBUTE + resource.getName();
190        copy.setId(id);
191    
192        URI location = UriBuilder.fromUri(request.getBaseURL()).path(
193            resource.getResourceDescriptor().getEndpoint()).path(id).build();
194        copy.setMeta(new Meta(null, null,location, null));
195    
196        // Pare down the attributes to those requested.
197        return ResourceDescriptor.RESOURCE_DESCRIPTOR_FACTORY.createResource(
198            resource.getResourceDescriptor(),
199            request.getAttributes().pareObject(copy.getScimObject()));
200      }
201    }