Error Generating a Discovery Doc from a backend API - google-cloud-endpoints

When executing this command from my ../war directory (from https://developers.google.com/appengine/docs/java/endpoints/endpoints_tool#generating_a_discovery_doc):
D:\programs\eclipse-kepler\plugins\com.google.appengine.eclipse.sdkbundle_1.9.4\appengine-java-sdk-1.9.4\bin\endpoints.cmd get-discovery-doc --format=rpc com.smartinteractive.blackwoods.entity.BranchEndpoint com.smartinteractive.blackwoods.PropertyEndpoint
this is the result:
V 08, 2014 9:31:11 AM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
INFO: Successfully processed ./war\WEB-INF/appengine-web.xml
Error: com.smartinteractive.blackwoods.entity.BranchEndpoint
I don't have a clue what kind of error this could be. I read in this topic (App engine RPC discovery doc) that
In the Endpoint methods, the return value type cannot be simple type
such as String or int. The return value needs to be a POJO, an array
or a Collection
What else could be the problem.
BranchEndpoint:
package com.smartinteractive.blackwoods.entity;
import com.smartinteractive.blackwoods.dao.service.BranchDataService;
import com.smartinteractive.blackwoods.persistence.EMF;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import com.google.api.server.spi.response.CollectionResponse;
import java.util.List;
import javax.annotation.Nullable;
import javax.inject.Named;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityNotFoundException;
import javax.persistence.EntityManager;
#Api(name = "branchendpoint", namespace = #ApiNamespace(ownerDomain = "smartinteractive.com", ownerName = "smartinteractive.com", packagePath = "blackwoods.entity"))
public class BranchEndpoint {
/**
* This method lists all the entities inserted in datastore.
* It uses HTTP GET method and paging support.
*
* #return A CollectionResponse class containing the list of all entities
* persisted
*/
#SuppressWarnings("unchecked")
#ApiMethod(name = "listBranch")
public CollectionResponse<Branch> listBranch(#Nullable #Named("first") Integer first, #Nullable #Named("last") Integer last) {
EntityManager mgr = getEntityManager();
List<Branch> execute = null;
try {
if(first == null || last == null) {
execute = new BranchDataService().findWithNamedQuery(Branch.ALL);
}
else {
execute = (List<Branch>)new BranchDataService().findAllBranches(mgr, first, last, null, null, null);
}
} finally {
mgr.close();
}
return CollectionResponse.<Branch> builder().setItems(execute).build();
}
/**
* This method gets the entity having primary key id. It uses HTTP GET method.
*
* #param id the primary key of the java bean.
* #return The entity with primary key id.
*/
#ApiMethod(name = "getBranch")
public Branch getBranch(#Named("id") Integer id) {
EntityManager mgr = getEntityManager();
Branch branch = null;
try {
branch = mgr.find(Branch.class, id);
} finally {
mgr.close();
}
return branch;
}
/**
* This inserts a new entity into App Engine datastore. If the entity already
* exists in the datastore, an exception is thrown.
* It uses HTTP POST method.
*
* #param branch the entity to be inserted.
* #return The inserted entity.
*/
#ApiMethod(name = "insertBranch")
public Branch insertBranch(Branch branch) {
EntityManager mgr = getEntityManager();
try {
if (containsBranch(branch)) {
throw new EntityExistsException("Object already exists");
}
mgr.persist(branch);
} finally {
mgr.close();
}
return branch;
}
/**
* This method is used for updating an existing entity. If the entity does not
* exist in the datastore, an exception is thrown.
* It uses HTTP PUT method.
*
* #param branch the entity to be updated.
* #return The updated entity.
*/
#ApiMethod(name = "updateBranch")
public Branch updateBranch(Branch branch) {
EntityManager mgr = getEntityManager();
try {
if (!containsBranch(branch)) {
throw new EntityNotFoundException("Object does not exist");
}
mgr.persist(branch);
} finally {
mgr.close();
}
return branch;
}
private boolean containsBranch(Branch branch) {
EntityManager mgr = getEntityManager();
boolean contains = true;
try {
Branch item = mgr.find(Branch.class, branch.getId());
if (item == null) {
contains = false;
}
} finally {
mgr.close();
}
return contains;
}
private static EntityManager getEntityManager() {
return EMF.get().createEntityManager();
}
}

Related

symonfy/doctrine, get associated entity return null , but return actual data if a call to `dump()` is added

This is one is a bit weird
I'm using symfony3/php7
I have the following ProUser entity linked to a Organization entity, used to identity pro account, (important part is the "isEnabled" method), when I try to login with a ProUser that has a linked Organization (they all have, but I made triple sure to choose one that had in database), I got an error that the organization is null, but if i had a dump method to debug, then the organization is correctly retrieved from database by doctrine...
/**
* Represent a professional owner (i.e a theater owner etc.)
*
* #ORM\Entity
* #ORM\Table(name="pro_user")
*/
class ProUser implements AdvancedUserInterface, \Serializable
{
/**
* #ORM\Column(name="id", type="guid")
* #ORM\Id
*/
protected $id;
/**
* #ORM\OneToOne(targetEntity="Organization", cascade={"persist"}, mappedBy="legalRepresentative")
*/
private $organization;
public function getOrganization()
{
return $this->organization;
}
public function setOrganization(Organization $organization)
{
$this->organization = $organization;
return $this;
}
/**
* Note: needed to implement the UserInterface
*/
public function getUsername()
{
return $this->email;
}
// for AdvancedUserInterface
public function isEnabled(): bool
{
$organization = $this->getOrganization();
// when this line is not present,
// it throws an exception that $organization is null,
// no problem when this line is present
dump($organization);
return $organization->isValidated();
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
}
The stacktrace :
Symfony\Component\Debug\Exception\FatalThrowableError:
Call to a member function isValidated() on null
at src/AppBundle/Entity/ProUser.php:151
at AppBundle\Entity\ProUser->isEnabled()
(vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php:277)
at Symfony\Component\Security\Core\Authentication\Token\AbstractToken->hasUserChanged(object(ProUser))
(vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php:101)
at Symfony\Component\Security\Core\Authentication\Token\AbstractToken->setUser(object(ProUser))
(vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/ContextListener.php:176)
at Symfony\Component\Security\Http\Firewall\ContextListener->refreshUser(object(RememberMeToken))
(vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/ContextListener.php:109)
at Symfony\Component\Security\Http\Firewall\ContextListener->handle(object(GetResponseEvent))
(vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php:46)
at Symfony\Bundle\SecurityBundle\Debug\WrappedListener->handle(object(GetResponseEvent))
(vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php:35)
at Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener->handleRequest(object(GetResponseEvent), object(RewindableGenerator))
(vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall.php:56)
at Symfony\Component\Security\Http\Firewall->onKernelRequest(object(GetResponseEvent))
(vendor/symfony/symfony/src/Symfony/Bundle/SecurityBundle/EventListener/FirewallListener.php:48)
Is it due to the code happening in the Security Component, and the entity was unserialized instead of being retrieved by doctrine, so that getOrganization() does not yet return a doctrine proxy ?
This is because of Doctrine's lazy loading of relations (it basically only knows the primary ids of the connected entities untill one or more of them are called, like with dump()).
You can add the fetch attribute to your mapping, where LAZY is default, you can set this to EAGER.

Symfony2 data transformer string to entity (reverseTransform)

I am pretty new to Symfony and hope someone can help me. I have an entity called Material and an associated entity called MaterialKeyword, which are basically tags. I am displaying the keywords comma delimited as a string in a text field on a form. I created a data transformer to do that. Pulling the keywords from the database and displaying them is no problem, but I have a problem with the reversTransform function when I want to submit existing or new keywords to the database.
Material class (MaterialKeyword):
/**
* #Assert\Type(type="AppBundle\Entity\MaterialKeyword")
* #Assert\Valid()
* #ORM\ManyToMany(targetEntity="MaterialKeyword", inversedBy="material")
* #ORM\JoinTable(name="materials_keyword_map",
* joinColumns={#ORM\JoinColumn(name="materialID", referencedColumnName="materialID", nullable=false)},
* inverseJoinColumns={#ORM\JoinColumn(name="keywordID", referencedColumnName="id", nullable=false)})
*/
public $materialkeyword;
/**
* Constructor
*/
public function __construct()
{
$this->MaterialKeyword = new ArrayCollection();
}
/**
* Set materialkeyword
*
* #param array $materialkeyword
*
*/
public function setMaterialkeyword(MaterialKeyword $materialkeyword=null)
{
$this->materialkeyword = $materialkeyword;
}
/**
* Get materialkeyword
*
* #Assert\Type("\array")
* #return array
*/
public function getMaterialkeyword()
{
return $this->materialkeyword;
}
Here is my code from the data transformer:
This part is working:
class MaterialKeywordTransformer implements DataTransformerInterface
{
/**
* #var EntityManagerInterface
*/
private $manager;
public function __construct(ObjectManager $manager)
{
$this->manager = $manager;
}
/**
* Transforms an object (materialkeyword) to a string.
*
* #param MaterialKeyword|null $materialkeyword
* #return string
*/
public function transform($material)
{
$result = array();
if (null === $material) {
return '';
}
foreach ($material as $materialkeyword) {
$result[] = $materialkeyword->getKeyword();
}
return implode(", ", $result);
}
This part is not working:
/**
* Transforms a string (keyword) to an object (materialkeyword).
*
* #param string $materialkeyword
* #return MaterialKeyword|null
* #throws TransformationFailedException if object (materialkeyword) is not found.
*/
public function reverseTransform($keywords)
{
// no keyword? It's optional, so that's ok
if (!$keywords) {
return;
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$keyword_array = explode(", ", $keywords);
foreach($keyword_array as $keyword){
$materialkeyword = new MaterialKeyword();
$keyword_entry = $repository->findBy(array('keyword' => $keyword));
if(array_key_exists(0, $keyword_entry)){
$keyword_entry_first = $keyword_entry[0];
}else{
$keyword_entry_first = $keyword_entry;
}
if (null === $keyword_entry_first) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keywords
));
}
$materialkeyword->setKeyword($keyword_entry_first);
}
return $materialkeyword;
}
There will be several keywords, so how do I store them. I tried Arrays and ArrayCollections (new ArrayCollection()) without any success.
The error that I am getting currently with the code above:
Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in /.../vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 605 and defined
TL;DR;
Your reverseTransform function should return an array containing zero or n MaterialKeyword.
It should not return a single MaterialKeyword object because the reverse transformation of MaterialKeyord[] --> string is not string --> MaterialKeyword, it is string --> MaterialKeyword[].
Thinking about this, the doctrine ArrayCollection exception you have make sense as it is trying to do new ArrayCollection(/** Single MaterialKeyword object */) instead of new ArrayCollection(/** Array of MaterialKeyword objects */).
From what you're telling I assume that Material and MaterialKeyword are connected by a ManyToMany association, in which case each Material has an array of MaterialKeyword objects associated to it.
Which means, that your Data Transformer should work with arrays as well, but you're only working with single objects.
Specifically, reverseTransform should return an array of MaterialKeyword objects, whereas you're only returning one (the last one handled in the loop.)
Another issue is that your method created new objects every time, even though $repository->findBy(...) would already return a MaterialKeyword instance. Creating a new object would cause that entry to be copied instead of simply used.
So the correct method might look like this:
public function reverseTransform($keywords)
{
// no keyword? It's optional, so that's ok
if (!$keywords) {
return array();
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$keyword_array = explode(", ", $keywords);
$result_list = array(); // This will contain the MaterialKeyword objects
foreach($keyword_array as $keyword){
$keyword_entry = $repository->findOneBy(array('keyword' => $keyword));
if (null === $keyword_entry) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keyword
));
}
$result_list[] = $keyword_entry;
}
return $result_list;
}
#Hanzi put me on the correct track. It has to be an array of MaterialKeywords objects.
Here is my final working code in class MaterialKeywordTransformer:
/**
* Transforms a string (keyword) to an object (materialkeyword).
*
* #param string $materialkeyword
* #return MaterialKeyword|null
* #throws TransformationFailedException if object (materialkeyword) is not found.
*/
public function reverseTransform($keywords)
{
// keyword are optional, so that's ok
if (!$keywords) {
return;
}
$repository = $this->manager
->getRepository('AppBundle:MaterialKeyword');
$repository_m = $this->manager
->getRepository('AppBundle:Material');
$keyword_array = explode(", ", $keywords);
foreach($keyword_array as $keyword){
$materialkeyword = new MaterialKeyword();
$materialkeyword->setKeyword($keyword);
if($this->opt["data"]->getMaterialID() !== null) {
$materialkeyword->setMaterialID($this->opt["data"]->getMaterialID());
} else {
$material = $repository_m->findOne();
$materialID = $material[0]->getMaterialID();
$materialkeyword->setMaterialID($materialID);
}
$materialkeywords[] = $materialkeyword;
if (null === $keywords) {
throw new TransformationFailedException(sprintf('There is no "%s" exists',
$keywords
));
}
}
return $materialkeywords;
}

Add dynamic property on entity to be serialized

I have this REST API. Whenever request comes to get a resource by id ( /resource/{id}) I want to add a permissions array on that object on the fly (entity itself does not have that field).
What I came up with is this event listener. It checks the result the controller has returned:
class PermissionFinderListener {
...
public function onKernelView(GetResponseForControllerResultEvent $event) {
$object = $event->getControllerResult();
if (!is_object($object) || !$this->isSupportedClass($object)) {
return;
}
$permissions = $this->permissionFinder->getPermissions($object);
$object->permissions = $permissions;
$event->setControllerResult($object);
}
....
}
The problem is that the JMS Serializer opts out this dynamic property on serialization. I tried making the onPostSerialize event subscriber on JMS serializer, but then there are no clear way to check if this is a GET ONE or GET COLLECTION request. I don't need this behaviour on GET COLLECTION and also it results a huge performance hit on collection serialization. Also I don't want to create any base entity class with permission property.
Maybe there is some other way to deal with this scenario?
What I could imagine is a combination of Virtual Property and Serialization Group:
Add a property to your entity like:
/**
* #Serializer\VirtualProperty
* #Serializer\SerializedName("permissions")
* #Serializer\Groups({"includePermissions"}) */
*
* #return string
*/
public function getPermissions()
{
return $permissionFinder->getPermissions($this);
}
Only thing you need to do then is to serialize 'includePermissions' group only in your special case (see http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies)
If you don't have access to $permissionFinder from your entity you could as well set the permission attribute of an entity from a Controller/Service before serializing it.
EDIT:
This is a bit more code to demonstrate what I mean by wrapping your entity and using VirtualProperty together with SerializationGroups. This code is not tested at all - it's basically a manually copied and stripped version of what we're using. So please use it just as an idea!
1) Create something like a wrapping class for your entity:
<?php
namespace Acquaim\ArcticBundle\Api;
use JMS\Serializer\Annotation as JMS;
/**
* Class MyEntityApi
*
* #package My\Package\Api
*/
class MyEntityApi
{
/**
* The entity which is wrapped
*
* #var MyEntity
* #JMS\Include()
*/
protected $entity;
protected $permissions;
/**
* #param MyEntity $entity
* #param Permission[] $permissions
*/
public function __construct(
MyEntity $entity,
$permissions = null)
{
$this->entity = $entity;
$this->permissions = $permissions;
}
/**
* #Serializer\VirtualProperty
* #Serializer\SerializedName("permissions")
* #Serializer\Groups({"includePermissions"})
*
* #return string
*/
public function getPermissions()
{
if ($this->permissions !== null && count($this->permissions) > 0) {
return $this->permissions;
} else {
return null;
}
}
/**
* #return object
*/
public function getEntity()
{
return $this->entity;
}
}
2) In your controller don't return your original Entity, but get your permissions and create your wrapped class with entity and permissions.
Set your Serialization Context to include permissions and let the ViewHandler return your serialized object.
If you don't set Serialization Context to includePermissions it will be excluded from the serialized result.
YourController:
$myEntity = new Entity();
$permissions = $this->get('permission_service')->getPermissions();
$context = SerializationContext::create()->setGroups(array('includePermissions'));
$myEntityApi = new MyEntityApi($myEntity,$permissions);
$view = $this->view($myEntityApi, 200);
$view->setSerializationContext($context);
return $this->handleView($view);

Doctrine2 EntityNotFoundException when getting an entity from relation

In a Symfony2 project using Doctrine2. I have a Lead entity related with Promotion entity 1-N. A Lead con have a related Promotion or not.
//Lead.php
...
/**
* #var string $promotionCode
* #ORM\Column(name="promotion_code", type="string", length=16)
*/
private $promotionCode;
/**
* #var Promotion $promotion
* #ORM\ManyToOne(targetEntity="Promotion")
* #ORM\JoinColumn(name="promotion_code", referencedColumnName="id")
*/
private $promotion;
...
public function setPromotionCode($promotionCode) {
$this->promotionCode = $promotionCode;
}
public function getPromotionCode() {
return $this->promotionCode;
}
public function setPromotion($promotion) {
$this->promotion = $promotion;
}
public function getPromotion() {
return $this->promotion;
}
When I want to obtain the related promotion (if any) y do
$lead = $em->getRepository('BuvMarketplaceBundle:Lead')->find($id);
$promotion = $lead->getPromotion();
If the lead has a promotion this is OK. But if not this code returns a Promotion "entity", but when I try to use if I get an EntityNotFoundException.
So I have to test if the related promotion exists like this:
if (is_object($promotion) && method_exists($promotion, 'getDiscount')) {
try {
$promotion->getDiscount();
} catch(EntityNotFoundException $e) {
$promotion = null;
}
} else {
$promotion = null;
}
I know that I can use a findBy in the Promotion Repository, and may be another methods to check this.
But the question is if this is a bug or a feature in Doctrine2, so I'm getting a "false entity" when I think it may be a null.

Using applicationComplete and initialize together in flex?

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" applicationComplete="init();" initialize="initializeHandler(event)">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import sandacreative.sqlite.events.StatementSuccessEvent;
import sandacreative.sqlite.SQLiteManager;
private var database:SQLiteManager = SQLiteManager.getInstance();
protected function initializeHandler(event:FlexEvent):void
{ trace("inside initializehandler");
database.start("Users.db", "Users", "CREATE TABLE Users(UserId VARCHAR(150) PRIMARY KEY, UserName VARCHAR(150))");
database.addEventListener(SQLiteManager.COMMAND_EXEC_SUCCESSFULLY, onSelectResult);
database.addEventListener(SQLiteManager.COMMAND_EXEC_FAILED, function():void {
trace("fail!");
});
readEntries();
}
private function insertEntry():void
{
var sql:String = "INSERT INTO Users VALUES('"+nameField.text+"');";
database.executeCustomCommand(sql);
}
// SQLite Ends Here*/
import flash.media.Camera;
import sandacreative.WebCam;
import sandacreative.Base64;
import mx.core.UIComponent;
import mx.graphics.codec.JPEGEncoder;
private var webCam:WebCam;
private function init():void {
webCam = new WebCam(160, 120);
var ref:UIComponent = new UIComponent();
preview.removeAllChildren();
preview.addChild(ref);
ref.addChild(webCam);
}
</fx:Script>
<mx:Panel width="180" height="160" id="preview" title="Snapshotr" x="158" y="343"/>
<mx:Button label="Save" id="submit" x="280" y="521" width="100" enabled="true" click="insertEntry();"/>
init() initiates a cam and that works properly .. while initiliseHandler() creates a sqlite table. But the table is not created and when i try to save it shows the error
Error: Error #3104: A SQLConnection must be open to perform this operation.
at Error$/throwError()
at flash.data::SQLStatement/checkAllowed()
at flash.data::SQLStatement/checkReady()
at flash.data::SQLStatement/execute()
at sandacreative.sqlite::SQLiteManager/executeCustomCommand()[C:\Documents and Settings\sujith\My Documents\Visitrac1\src\sandacreative\sqlite\SQLiteManager.as:238]
at sandacreative::Main/insertEntry()[C:\Documents and Settings\sujith\My Documents\Visitrac1\src\sandacreative\Main.mxml:34]
at sandacreative::Main/__submit_click()[C:\Documents and Settings\sujith\My Documents\Visitrac1\src\sandacreative\Main.mxml:153]
SQLiteManager.as
package sandacreative.sqlite
{
import sandacreative.sqlite.events.StatementSuccessEvent;
import flash.data.SQLConnection;
import flash.data.SQLStatement;
import flash.errors.SQLError;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.SQLErrorEvent;
import flash.events.SQLEvent;
import flash.filesystem.File;
public class SQLiteManager extends EventDispatcher implements ISQLiteManager
{
/**
* Database file name and extension
*/
public var dbFullFileName:String;
/**
* Database Name
*/
public var tableName:String;
/**
* SQL command to create the database
*/
public var createDbStatement:String;
// datsbase apis instances
protected var connection:SQLConnection;
protected var statement:SQLStatement;
protected var sqlFile:File;
// repeated sql command
protected var repeateFailCallBack:Function;
protected var repeateCallBack:Function;
protected var repeateSqlCommand:String = "";
// events strings
public static var COMMAND_EXEC_SUCCESSFULLY:String = "commandExecSuccesfully";
public static var DATABASE_CONNECTED_SUCCESSFULLY:String = "databaseConnectedSuccessfully";
public static var COMMAND_EXEC_FAILED:String = "commandExecFailed";
public static var DATABASE_READY:String = "databaseReady";
// Singleton instance.
protected static var instance:SQLiteManager;
/**
* Enforce singleton design pattern.
*
* #param enforcer
*
*/
public function SQLiteManager(enforcer:AccessRestriction)
{
if (enforcer == null)
throw new Error("Error enforcer input param is undefined" );
}
/**
* Opens a database connection.
*
* #param dbFullFileName the database file name for instance: Users.sql
* #param tableName holds the database name, for instance: Users
* #param createTableStatement holds the create database statment for instance: CREATE TABLE Users(userId VARCHAR(150) PRIMARY KEY, UserName VARCHAR(150))
*
*/
public function start(dbFullFileName:String, tableName:String, createTableStatement:String):void
{
this.dbFullFileName = dbFullFileName;
this.tableName = tableName;
this.createDbStatement = createTableStatement;
connection = new SQLConnection();
sqlFile = File.applicationStorageDirectory.resolvePath(dbFullFileName);
try
{
connection.open(sqlFile);
this.dispatchEvent(new Event(DATABASE_CONNECTED_SUCCESSFULLY));
}
catch (error:SQLError)
{
trace("Error message:", error.message);
trace("Details:", error.details);
fail();
}
}
/**
* Close connection
*
*/
public function close():void
{
connection.close();
}
/**
* Test the table to ensure it exists. Sends a fail call back function to create the table if
* it doesn't exists.
*
*/
public function testTableExists():void
{
var sql:String = "SELECT * FROM "+tableName+" LIMIT 1;";
executeCustomCommand(sql, this.onDatabaseReady, this.createTable );
}
/**
* Method to create the database table.
*
*/
private function createTable():void
{
statement = new SQLStatement();
statement.sqlConnection = connection;
statement.text = createDbStatement;
statement.execute();
statement.addEventListener(SQLEvent.RESULT, onDatabaseReady);
}
/**
* Common sql command: select all entries in database
*
* #param callback
* #param failCallback
*
*/
public function executeSelectAllCommand(callback:Function=null, failCallback:Function=null):void
{
var sql:String = "SELECT * FROM "+tableName+";";
executeCustomCommand(sql, callback, failCallback);
}
/**
* Common sql command: delete all entries in database
*
* #param callback
*
*/
public function executeDeleteAllCommand(callback:Function=null):void
{
var sql:String = "DELETE * FROM "+tableName+";";
executeCustomCommand(sql, callback);
}
/**
* Method to execute a SQL command
*
* #param sql SQL command string
* #param callback success call back function to impliment if necessery
* #param failCallBack fail call back function to impliment if necessery
*
*/
public function executeCustomCommand(sql:String, callBack:Function=null, failCallBack:Function=null):void
{
statement = new SQLStatement();
statement.sqlConnection = connection;
statement.text = sql;
if (callBack!=null)
{
statement.addEventListener(SQLEvent.RESULT, callBack);
}
else
{
statement.addEventListener(SQLEvent.RESULT, onStatementSuccess);
}
statement.addEventListener(SQLErrorEvent.ERROR, function():void {
fail();
});
try
{
statement.execute();
}
catch (error:SQLError)
{
this.handleErrors(error, sql, callBack, failCallBack);
}
}
/**
* Utility method to clean bad characters that can break SQL commands
*
* #param str
* #return
*
*/
public static function removeBadCharacters(str:String):String
{
var retVal:String = str.split("'").join("’’");
return retVal;
}
// ------------------------------HANDLERS----------------------------
/**
* Method to handle SQL command that create the dataabase.
* If the method was created due to a fail SQL command method checks if need to repeate any SQL command.
*
* #param event
*
*/
private function onDatabaseReady(event:Event=null):void
{
var evt:Event = new Event(DATABASE_READY);
this.dispatchEvent(evt);
if (repeateSqlCommand != "")
{
this.executeCustomCommand(repeateSqlCommand, repeateCallBack, repeateFailCallBack);
repeateSqlCommand = "";
repeateFailCallBack = null;
repeateCallBack = null;
}
}
/**
* Handle successful calls
* #param event
*
*/
private function onStatementSuccess(event:SQLEvent):void
{
var results:Object = statement.getResult();
var evt:StatementSuccessEvent = new StatementSuccessEvent(COMMAND_EXEC_SUCCESSFULLY, results);
this.dispatchEvent(evt);
}
/**
* Error handler
*
* #param error
* #param sql
* #param callBack
* #param failCallBack
*
*/
private function handleErrors(error:SQLError, sql:String, callBack:Function, failCallBack:Function):void
{
trace("Error message:", error.message);
trace("Details:", error.details);
if (error.details == "no such table: '"+tableName+"'")
{
repeateSqlCommand = sql;
repeateFailCallBack = failCallBack;
repeateCallBack = callBack;
createTable();
}
else
{
if (failCallBack != null)
{
failCallBack();
}
else
{
fail();
}
}
}
/**
* Handler for fail calls
*
* #param event
*
*/
private function fail(event:Event=null):void
{
var evt:Event = new Event(COMMAND_EXEC_FAILED);
this.dispatchEvent(evt);
close();
}
/**
* Method function to retrieve instance of the class
*
* #return The same instance of the class
*
*/
public static function getInstance():SQLiteManager
{
if( instance == null )
instance = new SQLiteManager(new AccessRestriction());
return instance;
}
}
}
class AccessRestriction {} // can this happen ?
ISQLiteManager.as
package sandacreative.sqlite
{
/**
* Describes the contract for Objects that serve as a central point to access SQLite database.
*
* #author Elad Elrom
*
*/
public interface ISQLiteManager
{
function start(dbFullFileName:String, tableName:String, createTableStatement:String):void
function close():void
}
}
StatementSucessEvent.as
package sandacreative.sqlite.events
{
import flash.events.Event;
public class StatementSuccessEvent extends Event
{
/**
* Holds the event string name
*/
public static var COMMAND_EXEC_SUCCESSFULLY:String = "command_exec_succesfully";
/**
* Holds results object
*/
public var results:Object;
/**
* Default constructor
*
* #param type event name
* #param videoList video list collection
*
*/
public function StatementSuccessEvent(type:String, results:Object)
{
super(type);
this.results = results;
}
}
}
I took this code from Elad Elrom
Is that because i used both applicationComplete and Initilize together ? Please help
The error is kind of obvious. Your database hasn't been created/connected yet before your button is pressed. Also, the createTable function is never called because you never keep state on your connection property.
Before any statement is executed, you should always check that the DB is connected. For all you know, the connection failed.
And thirdly (and probably most important), you are doing a synchronous execution because you used connection.open. For this to work, you need to do connection.begin() before executing any statements and finish with connection.commit(). I think the better way for you to go here is to use connection.openAsync instead to create an asynchronous execution which is easier to manage and probably what you wanted to do. Only use synchronous if the order of the statements are important (like in a transaction or if one statement is dependent on another).

Resources