/* * Copyright (C) 2012 The Android Open Source Project * * 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. */ package com.motorola.studio.android.db.deployment; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.osgi.util.NLS; import com.motorola.studio.android.codeutils.db.utils.DatabaseUtils; import com.motorola.studio.android.codeutils.i18n.CodeUtilsNLS; import com.motorola.studio.android.common.IAndroidConstants; import com.motorola.studio.android.common.exception.AndroidException; import com.motorola.studio.android.common.utilities.FileUtil; import com.motorola.studio.android.manifest.AndroidProjectManifestFile; import com.motorola.studio.android.model.manifest.AndroidManifestFile; import com.motorola.studio.android.model.manifest.dom.ApplicationNode; import com.motorola.studio.android.model.manifest.dom.ManifestNode; import com.motorola.studio.android.model.manifest.dom.ProviderNode; /** * Creates Content Provider that have methods to copy .db file. */ public class ContentProviderDeployer { /* * Plug-in Identifier */ private static final String PLUGIN_IDENTIFIER = "com.motorola.studio.android.codeutils"; /** * Constant representing the location of the DataaseHelper class. */ public static final String CONTENT_PROVIDER_HELPER_CLASS_LOCATION = "resources/databaseDeploy/ContentProviderHelperjava.txt"; //$NON-NLS-1$ /** * This constant represents the value of newly-create Application Package Name for the Content Provider. */ public static final String APPLICATION_PACKAGE_NAMESPACE = "#applicationPackageNamespace#"; /** * Directory of the ContentProvider Helper in the android project. */ public static final String ANDROID_PROJECT_PACKAGE_NAME = "#packageName#"; //$NON-NLS-1$ /** * File name of the ContentProvider Helper in the android project. */ public static final String CONTENT_PROVIDER_CLASS_NAME = "#className#"; //$NON-NLS-1$ public static final String CONTENT_PROVIDER_AUTHORITY = "#authority#"; //$NON-NLS-1$ /** * Copy the ContentProvider Helper deploy file to the newly-created-android project. * * @param project Project where the files will be copied to * @param parameters Copy parameters * @param templateLocation The template (origin) location * @param needToAddOnManifest <code>true</code> in case the manifest is to be updated, false otherwise * @param overrideConentProviderIfExists <code>true</code> in case the Content Providers must be overridden * in case they exist * @param monitor UI monitor * * @throws IOException Exception thrown in case there are problems accessing data of a file. * @throws CoreException Exception thrown in case there are problems accessing a file itself. */ public static void copyContentProviderHelperClassToProject(IProject project, Map<String, String> parameters, String templateLocation, boolean needToAddOnManifest, boolean overrideConentProviderIfExists, IProgressMonitor monitor) throws IOException, CoreException { // get the destination folder IFolder destinationFolder = project.getFolder(IAndroidConstants.WS_ROOT + IAndroidConstants.FD_SOURCES); // split the new sequence of folders - they will be created, one by one String[] folders = parameters.get(ANDROID_PROJECT_PACKAGE_NAME).split(IAndroidConstants.RE_DOT); // iterate through the folders and create them if ((folders != null) && (folders.length > 0)) { // iterate for (String folder : folders) { // get destination folder with the next one to be created destinationFolder = destinationFolder.getFolder(folder); // proceed in case the destination folder does not exists and can be created if (!destinationFolder.exists()) { // create the folder destinationFolder.create(true, true, monitor); } } } // get the destination file IFile destinationFile = destinationFolder.getFile(parameters.get(CONTENT_PROVIDER_CLASS_NAME) + IAndroidConstants.DOT_JAVA); //refresh to avoid inconsistency destinationFile.getParent().refreshLocal(IResource.DEPTH_INFINITE, monitor); // proceed in case it does not exist and can be created if ((!destinationFile.exists() || overrideConentProviderIfExists) && FileUtil.canWrite(destinationFile)) { // get the Database Helper class as a text String databaseHelperText = readContentProviderHelperClassFile(project, parameters, templateLocation); // transform it in a stream InputStream stream = null; try { stream = new ByteArrayInputStream(databaseHelperText.getBytes("UTF-8")); //$NON-NLS-1$ // if the file exists, delete it if (destinationFile.exists()) { destinationFile.delete(true, monitor); } // create the destination file destinationFile.create(stream, true, monitor); DatabaseUtils.formatCode(destinationFile, databaseHelperText, monitor); } finally { if (stream != null) { stream.close(); } } } if (needToAddOnManifest) { try { String className = parameters.get(CONTENT_PROVIDER_CLASS_NAME); String packageName = parameters.get(ANDROID_PROJECT_PACKAGE_NAME); createProviderOnManifest(project, className, packageName, monitor); } catch (AndroidException e) { throw new IOException(e.getMessage()); } } } /** * Read the ContentProvider Helper class file, replace the parameter maps * and return it as a String. * * @param project Project where the ContentProviderHelper is retrieved. * @param parameters Parameters for replacement in the ContentProviderHelper class file. * * @return a String representing the ContentProviderHelper class file. * * @throws IOException Exception thrown when there are problems reading elements from the * ContentProviderHelper class file. */ private static String readContentProviderHelperClassFile(IProject project, Map<String, String> parameters, String templateLocation) throws IOException { URL url = Platform.getBundle(PLUGIN_IDENTIFIER).getEntry(templateLocation); url = FileLocator.toFileURL(url); // string buffer which holds the file as a text StringBuffer contentProviderHelperBuffer = new StringBuffer(""); // reader BufferedReader contentProviderHelperReader = null; // get the file to be read File f = null; try { f = new File(url.getFile()); // create the reader to manipulate the file contentProviderHelperReader = new BufferedReader(new FileReader(f)); // read the Database Helper class file in steps (using buffer) String buffer = null; // iterate while there is stuff to read while ((buffer = contentProviderHelperReader.readLine()) != null) { // read and put the content in the string buffer element contentProviderHelperBuffer.append(buffer); contentProviderHelperBuffer.append(System.getProperty("line.separator")); } } finally { // close reader if (contentProviderHelperReader != null) { contentProviderHelperReader.close(); } } // string holding the "text" of the ContentProvider class String contentProviderHelperText = ""; // proceed in case there is stuff in the buffer to read if (contentProviderHelperBuffer != null) { contentProviderHelperText = contentProviderHelperBuffer.toString(); // iterate through the parameters and replace the parameters in the map if (parameters != null) { for (String key : parameters.keySet()) { // replace all the keys contentProviderHelperText = contentProviderHelperText.replaceAll(key, parameters.get(key)); } } } // return the file as a text return contentProviderHelperText; } /** * Creates the Content Provider class entry on AndroidManifest.xml file * * @param monitor the progress monitor * * @return true if the entry has been added or false otherwise * @throws AndroidException */ private static boolean createProviderOnManifest(IProject project, String className, String packageName, IProgressMonitor monitor) throws AndroidException { boolean created = false; try { int manifestUpdatingSteps = 4; int totalWork = manifestUpdatingSteps; monitor.beginTask("", totalWork); monitor.subTask(CodeUtilsNLS.UI_Common_UpdatingTheAndroidManifestXMLFile); AndroidManifestFile androidManifestFile = AndroidProjectManifestFile.getFromProject(project); monitor.worked(1); ManifestNode manifestNode = androidManifestFile != null ? androidManifestFile.getManifestNode() : null; ApplicationNode applicationNode = manifestNode != null ? manifestNode.getApplicationNode() : null; monitor.worked(1); if (applicationNode != null) { ProviderNode providerNode = new ProviderNode(className, packageName + "." + className.toLowerCase()); String authority = packageName + "." + className.toLowerCase(); providerNode.addAuthority(authority); String name = packageName + "." + className; providerNode.setName(name); // get all provider nodes List<ProviderNode> providerNodes = applicationNode.getProviderNodes(); // see whether the node to be inserted is already in the list - in case it is not, add it, otherwise do nothing boolean hasProviderNode = false; // verify in case the list of nodes is not empty if ((providerNodes != null) && (providerNodes.size() > 0)) { // iterate through the list for (ProviderNode retrievedProvidedNode : providerNodes) { // match the nodes if (retrievedProvidedNode.getName().equals(providerNode.getName())) { // in case a match is found, set the flag and leave the loop hasProviderNode = true; break; } } } // in case there is not this provider node, add it if (!hasProviderNode) { applicationNode.addProviderNode(providerNode); } monitor.worked(1); monitor.subTask(CodeUtilsNLS.UI_Common_SavingTheAndroidManifestXMLFile); AndroidProjectManifestFile.saveToProject(project, androidManifestFile, true); created = true; monitor.worked(1); } } catch (AndroidException e) { String errMsg = NLS.bind(CodeUtilsNLS.EXC_ContentProvider_CannotUpdateTheManifestFile, className, e.getLocalizedMessage()); throw new AndroidException(errMsg); } catch (CoreException e) { String errMsg = NLS.bind(CodeUtilsNLS.EXC_ContentProvider_CannotUpdateTheManifestFile, className, e.getLocalizedMessage()); throw new AndroidException(errMsg); } finally { monitor.done(); } return created; } }