Refactor search process (#188)

Extract service search method from controller to service.
Fix bug: origin method cannot find services with upper case service name;e.g: filter like *ExampleService cannot get xxx.ExampleService.
Add some comments.
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
index c3cd74f..8dd6358 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
@@ -53,57 +53,11 @@
     @RequestMapping(method = RequestMethod.GET)
     public Set<ServiceDTO> searchService(@RequestParam String pattern,
                                          @RequestParam String filter,@PathVariable String env) {
-
-        List<Provider> providers = new ArrayList<>();
-        if (!filter.contains(Constants.ANY_VALUE) && !filter.contains(Constants.INTERROGATION_POINT)) {
-            if (Constants.IP.equals(pattern)) {
-                providers = providerService.findByAddress(filter);
-            } else if (Constants.SERVICE.equals(pattern)) {
-                providers = providerService.findByService(filter);
-            } else if (Constants.APPLICATION.equals(pattern)) {
-                providers = providerService.findByApplication(filter);
-            }
-        } else {
-            List<String> candidates = Collections.emptyList();
-            if (Constants.SERVICE.equals(pattern)) {
-                candidates = providerService.findServices();
-            } else if (Constants.APPLICATION.equals(pattern)) {
-                candidates = providerService.findApplications();
-            }
-            filter = filter.toLowerCase().replace(Constants.PUNCTUATION_POINT, Constants.PUNCTUATION_SEPARATOR_POINT);
-            if (filter.startsWith(Constants.ANY_VALUE)) {
-                filter = Constants.PUNCTUATION_POINT + filter;
-            }
-            Pattern regex = Pattern.compile(filter);
-            for (String candidate : candidates) {
-                Matcher matcher = regex.matcher(candidate);
-                if (matcher.matches() || matcher.lookingAt()) {
-                    if (Constants.SERVICE.equals(pattern)) {
-                        providers.addAll(providerService.findByService(candidate));
-                    } else {
-                        providers.addAll(providerService.findByApplication(candidate));
-                    }
-                }
-            }
-        }
-
-        Set<ServiceDTO> result = new TreeSet<>();
-        for (Provider provider : providers) {
-            Map<String, String> map = StringUtils.parseQueryString(provider.getParameters());
-            String app = provider.getApplication();
-            String service = map.get(Constants.INTERFACE_KEY);
-            String group = map.get(Constants.GROUP_KEY);
-            String version = map.get(Constants.VERSION_KEY);
-            ServiceDTO s = new ServiceDTO();
-            s.setAppName(app);
-            s.setService(service);
-            s.setGroup(group);
-            s.setVersion(version);
-            result.add(s);
-        }
-        return result;
+        return providerService.getServiceDTOS(pattern, filter, env);
     }
 
+
+
     @RequestMapping(value = "/{service}", method = RequestMethod.GET)
     public ServiceDetailDTO serviceDetail(@PathVariable String service, @PathVariable String env) {
         service = service.replace(Constants.ANY_VALUE, Constants.PATH_SEPARATOR);
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ProviderService.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
index eafb6d0..01a79e4 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/ProviderService.java
@@ -17,9 +17,11 @@
 package org.apache.dubbo.admin.service;
 
 import org.apache.dubbo.admin.model.domain.Provider;
+import org.apache.dubbo.admin.model.dto.ServiceDTO;
 import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * ProviderService
@@ -45,6 +47,11 @@
 
     String getProviderMetaData(MetadataIdentifier providerIdentifier);
 
+    /**
+     * Get all provider's service name
+     *
+     * @return list of all provider's service name
+     */
     List<String> findServices();
 
     String findServiceVersion(String serviceName, String application);
@@ -59,18 +66,36 @@
 
     List<String> findApplicationsByServiceName(String serviceName);
 
+    /**
+     * Get provider list with specific service name.
+     *
+     * @param serviceName specific service name, cannot be fuzzy string
+     * @return list of provider object
+     */
     List<Provider> findByService(String serviceName);
 
     List<Provider> findByAppandService(String app, String serviceName);
 
     List<Provider> findAll();
 
+    /**
+     * Get provider list with specific ip address.
+     *
+     * @param providerAddress provider's ip address
+     * @return list of provider object
+     */
     List<Provider> findByAddress(String providerAddress);
 
     List<String> findServicesByAddress(String providerAddress);
 
     List<String> findApplications();
 
+    /**
+     * Get provider list with specific application name.
+     *
+     * @param application specific application name
+     * @return list of provider object
+     */
     List<Provider> findByApplication(String application);
 
     List<String> findServicesByApplication(String application);
@@ -79,4 +104,17 @@
 
     Provider findByServiceAndAddress(String service, String address);
 
-}
+    /**
+     * Get a set of service data object.
+     *
+     * ServiceDTO object contains base information include
+     * service name , application, group and version.
+     *
+     * @param pattern {@code String} type of search
+     * @param filter  {@code String} input filter string
+     * @param env     {@code String}the environment of front end
+     * @return a set of services for fore-end page
+     */
+    Set<ServiceDTO> getServiceDTOS(String pattern, String filter, String env);
+
+}
\ No newline at end of file
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
index 09670c8..0eafc9a 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
@@ -24,6 +24,7 @@
 import org.apache.dubbo.admin.common.util.ParseUtils;
 import org.apache.dubbo.admin.common.util.SyncUtils;
 import org.apache.dubbo.admin.model.domain.Provider;
+import org.apache.dubbo.admin.model.dto.ServiceDTO;
 import org.apache.dubbo.admin.service.OverrideService;
 import org.apache.dubbo.admin.service.ProviderService;
 import org.apache.dubbo.common.Constants;
@@ -35,12 +36,11 @@
 import org.springframework.stereotype.Component;
 import org.yaml.snakeyaml.events.Event;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import static org.apache.dubbo.common.Constants.SPECIFICATION_VERSION_KEY;
 
@@ -506,4 +506,69 @@
         }
     }
 
+    public Set<ServiceDTO> getServiceDTOS(String pattern, String filter, String env) {
+        List<Provider> providers = new ArrayList<>();
+        if (!filter.contains("*") && !filter.contains("?")) {
+            // filter with specific string
+            if (org.apache.dubbo.admin.common.util.Constants.IP.equals(pattern)) {
+                providers = findByAddress(filter);
+            } else if (org.apache.dubbo.admin.common.util.Constants.SERVICE.equals(pattern)) {
+                providers = findByService(filter);
+            } else if (org.apache.dubbo.admin.common.util.Constants.APPLICATION.equals(pattern)) {
+                providers = findByApplication(filter);
+            }
+        } else {
+            // filter with fuzzy search
+            List<String> candidates = Collections.emptyList();
+            if (org.apache.dubbo.admin.common.util.Constants.SERVICE.equals(pattern)) {
+                candidates = findServices();
+            } else if (org.apache.dubbo.admin.common.util.Constants.APPLICATION.equals(pattern)) {
+                candidates = findApplications();
+            }
+            // replace dot symbol and asterisk symbol to java-based regex pattern
+            filter = filter.toLowerCase().replace(".", "\\.");
+            if (filter.startsWith("*")) {
+                filter = "." + filter;
+            }
+            Pattern regex = Pattern.compile(filter, Pattern.CASE_INSENSITIVE); // search with no case insensitive
+            for (String candidate : candidates) {
+                Matcher matcher = regex.matcher(candidate);
+                if (matcher.matches() || matcher.lookingAt()) {
+                    if (org.apache.dubbo.admin.common.util.Constants.SERVICE.equals(pattern)) {
+                        providers.addAll(findByService(candidate));
+                    } else {
+                        providers.addAll(findByApplication(candidate));
+                    }
+                }
+            }
+        }
+
+        Set<ServiceDTO> result = convertProviders2DTO(providers);
+        return result;
+    }
+
+    /**
+     * Convert provider list to ServiceDTO list
+     *
+     * @param providers list of providers
+     * @return ServiceDTO list of front page
+     */
+    public Set<ServiceDTO> convertProviders2DTO(List<Provider> providers) {
+        Set<ServiceDTO> result = new TreeSet<>();
+        for (Provider provider : providers) {
+            Map<String, String> map = StringUtils.parseQueryString(provider.getParameters());
+            String app = provider.getApplication();
+            String service = map.get(Constants.INTERFACE_KEY);
+            String group = map.get(Constants.GROUP_KEY);
+            String version = map.get(Constants.VERSION_KEY);
+            ServiceDTO s = new ServiceDTO();
+            s.setAppName(app);
+            s.setService(service);
+            s.setGroup(group);
+            s.setVersion(version);
+            result.add(s);
+        }
+        return result;
+    }
+
 }