String link()

in grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/DefaultLinkGenerator.groovy [108:291]


    String link(Map attrs, String encoding = 'UTF-8') {
        def writer = new StringBuilder()
        // prefer URI attribute
        boolean includeContext = GrailsClassUtils.getBooleanFromMap(ATTRIBUTE_INCLUDE_CONTEXT, attrs, true)

        if (attrs.get(ATTRIBUTE_URI) != null) {
            def uri = attrs.get(ATTRIBUTE_URI).toString()
            if(!isUriAbsolute(uri)){
                final base = handleAbsolute(attrs)
                if (base != null) {
                    writer.append base
                }
                else if(includeContext) {

                    def cp = attrs.get(ATTRIBUTE_CONTEXT_PATH)
                    if (cp == null) cp = getContextPath()
                    if (cp != null)
                        writer.append cp
                }
            }
            writer.append uri
            
            def params = attrs.get(ATTRIBUTE_PARAMS)

            if(params instanceof Map) {
                def charset = GrailsWebUtil.DEFAULT_ENCODING
                def paramString = params.collect { Map.Entry entry ->
                    def encodedKey = URLEncoder.encode(entry.key as String, charset)
                    def encodedValue = URLEncoder.encode(entry.value as String, charset)
                    "$encodedKey=$encodedValue"
                }.join('&')
                writer.append(uri.indexOf('?') >= 0 ? '&' : '?')
                      .append paramString
            }
        }
        else if (attrs.get(ATTRIBUTE_RELATIVE_URI) != null) {
            String relativeUri = attrs.get(ATTRIBUTE_RELATIVE_URI)
            String forwardUri = WebUtils.getForwardURI(requestStateLookupStrategy.webRequest.request)
            int index = forwardUri.lastIndexOf('/')
            if (index != -1) {
                writer.append forwardUri.substring(0, index + 1)
            }
            writer.append relativeUri
        }
        else {
            // prefer a URL attribute
            Map urlAttrs = attrs
            final urlAttribute = attrs.get(ATTRIBUTE_URL)
            if (urlAttribute instanceof Map) {
                urlAttrs = (Map)urlAttribute
            }
            if (!urlAttribute || urlAttribute instanceof Map) {
                final controllerAttribute = urlAttrs.get(ATTRIBUTE_CONTROLLER)
                final resourceAttribute = urlAttrs.get(ATTRIBUTE_RESOURCE)
                String controller
                String action = urlAttrs.get(ATTRIBUTE_ACTION)?.toString()
                def id = urlAttrs.get(ATTRIBUTE_ID)
                String httpMethod;
                final methodAttribute = urlAttrs.get(ATTRIBUTE_METHOD)
                final paramsAttribute = urlAttrs.get(ATTRIBUTE_PARAMS)
                Map params = paramsAttribute instanceof Map ? (Map) paramsAttribute : [:]

                if (resourceAttribute) {
                    String resource
                    if (resourceAttribute instanceof CharSequence)
                        resource = resourceAttribute.toString()
                    else {
                        PersistentEntity persistentEntity = (mappingContext != null) ? mappingContext.getPersistentEntity(resourceAttribute.getClass().getName()) : null
                        boolean hasId = false
                        if(persistentEntity != null) {
                            resource = persistentEntity.getDecapitalizedName()
                            hasId = true
                        } else if (DomainClassArtefactHandler.isDomainClass(resourceAttribute.getClass(), true)) {
                            resource = GrailsNameUtils.getPropertyName(resourceAttribute.getClass())
                            hasId = true
                        } else if (resourceAttribute instanceof Class) {
                            resource = GrailsNameUtils.getPropertyName(resourceAttribute)
                        } else {
                            resource = resourceAttribute.toString()
                        }
                        if(!id && hasId) {
                            id = getResourceId(resourceAttribute)
                        }
                    }
                    List tokens = resource.contains('/') ?  resource.tokenize('/') :[resource]
                    controller = controllerAttribute?:tokens[-1]
                    if (tokens.size()>1) {
                        for(t in tokens[0..-2]) {
                            final key = "${t}Id".toString()
                            final attr = urlAttrs.remove(key)
                            // the params value might not be null
                            // only overwrite if urlAttrs actually had the key
                            if (attr) {
                                params[key] = attr
                            }
                        }
                    }
                    if (!methodAttribute && action) {
                        httpMethod =  REST_RESOURCE_ACTION_TO_HTTP_METHOD_MAP.get(action.toString())
                        if (!httpMethod) {
                            httpMethod = HttpMethod.GET.toString()
                        }
                    }
                    else if (methodAttribute && !action) {
                        def method = methodAttribute.toString().toUpperCase()
                        httpMethod = method
                        if (method == 'GET' && id) method = "${method}_ID".toString()
                        action = REST_RESOURCE_HTTP_METHOD_TO_ACTION_MAP[method]
                    }
                    else {
                        httpMethod = methodAttribute == null ? requestStateLookupStrategy.getHttpMethod() ?: UrlMapping.ANY_HTTP_METHOD : methodAttribute.toString()
                    }

                }
                else {
                    controller = controllerAttribute == null ? requestStateLookupStrategy.getControllerName() : controllerAttribute.toString()
                    httpMethod = methodAttribute == null ? requestStateLookupStrategy.getHttpMethod() ?: UrlMapping.ANY_HTTP_METHOD : methodAttribute.toString()
                }


                String convertedControllerName = grailsUrlConverter.toUrlElement(controller)

                boolean isDefaultAction = false
                if (controller && !action) {
                    action = requestStateLookupStrategy.getActionName(convertedControllerName)
                    isDefaultAction = true
                }
                String convertedActionName = action
                if (action) {
                    convertedActionName = grailsUrlConverter.toUrlElement(action)
                }

                String frag = urlAttrs.get(ATTRIBUTE_FRAGMENT)?.toString()


                def mappingName = urlAttrs.get(ATTRIBUTE_MAPPING)
                if (mappingName != null) {
                    params.mappingName = mappingName
                }
                def url
                if (id != null) {
                    params.put(ATTRIBUTE_ID, id)
                }
                def pluginName = attrs.get(UrlMapping.PLUGIN)?.toString()
                def namespace = attrs.get(UrlMapping.NAMESPACE)?.toString()
                if (namespace == null) {
                    if (controller == requestStateLookupStrategy.controllerName) {
                        namespace = requestStateLookupStrategy.controllerNamespace
                    }
                }
                UrlCreator mapping = urlMappingsHolder.getReverseMappingNoDefault(controller,action,namespace,pluginName,httpMethod,params)
                if (mapping == null && isDefaultAction) {
                    mapping = urlMappingsHolder.getReverseMappingNoDefault(controller,null,namespace,pluginName,httpMethod,params)
                }
                if (mapping == null) {
                    mapping = urlMappingsHolder.getReverseMapping(controller,action,namespace,pluginName,httpMethod,params)
                }

                boolean absolute = isAbsolute(attrs)

                if (!absolute) {
                    url = mapping.createRelativeURL(convertedControllerName, convertedActionName, namespace, pluginName, params, encoding, frag)
                    final contextPathAttribute = attrs.get(ATTRIBUTE_CONTEXT_PATH)
                    final cp = contextPathAttribute == null ? getContextPath() : contextPathAttribute
                    if (attrs.get(ATTRIBUTE_BASE) || cp == null) {
                        attrs.put(ATTRIBUTE_ABSOLUTE, true)
                        writer.append handleAbsolute(attrs)
                    }
                    else if(includeContext) {
                        writer.append cp
                    }
                    writer.append url
                }
                else {
                    url = mapping.createRelativeURL(convertedControllerName, convertedActionName, namespace, pluginName, params, encoding, frag)
                    writer.append handleAbsolute(attrs)
                    writer.append url
                }
            } else {
                writer.append urlAttribute
            }
        }
        return writer.toString()
    }